Auto merge of #32293 - nikomatsakis:incr-comp-def-path-munging, r=alexcrichton

Revamp symbol names for impls (and make them deterministic, etc)

This builds on @michaelwoerister's epic PR #31539 (note that his PR never landed, so I just incorporated it into this one). The main change here is that we remove the "name" from `DefPathData` for impls, since that name is synthetic and not sufficiently predictable for incr comp. However, just doing that would cause bad symbol names since those are based on the `DefPath`. Therefore, I introduce a new mechanism for getting symbol names (and also paths for user display) called `item_path`. This is kind of simplistic for now (based on strings) but I expect to expand it later to support richer types, hopefully generating C++-mangled names that gdb etc can understand. Along the way I cleaned up how we track the path that leads to an extern crate.

There is still some cleanup left undone here. Notably, I didn't remove the impl names altogether -- that would probably make sense. I also didn't try to remove the `item_symbols` vector. Mostly I want to unblock my other incr. comp. work. =)

r? @eddyb
cc @eddyb @alexcrichton @michaelwoerister
This commit is contained in:
bors 2016-03-25 18:09:28 -07:00
commit 8d2d2be6c6
96 changed files with 1833 additions and 659 deletions

View File

@ -383,7 +383,7 @@ $(3)/stage$(1)/test/$(4)test-$(2)$$(X_$(2)): \
@$$(call E, rustc: $$@)
$(Q)CFG_LLVM_LINKAGE_FILE=$$(LLVM_LINKAGE_PATH_$(2)) \
$$(subst @,,$$(STAGE$(1)_T_$(2)_H_$(3))) -o $$@ $$< --test \
-L "$$(RT_OUTPUT_DIR_$(2))" \
-Cmetadata="test-crate" -L "$$(RT_OUTPUT_DIR_$(2))" \
$$(LLVM_LIBDIR_RUSTFLAGS_$(2)) \
$$(RUSTFLAGS_$(4))

View File

@ -69,10 +69,10 @@ impl fmt::Display for Mode {
#[derive(Clone)]
pub struct Config {
// The library paths required for running the compiler
pub compile_lib_path: String,
pub compile_lib_path: PathBuf,
// The library paths required for running compiled programs
pub run_lib_path: String,
pub run_lib_path: PathBuf,
// The rustc executable
pub rustc_path: PathBuf,

View File

@ -118,9 +118,17 @@ pub fn parse_config(args: Vec<String> ) -> Config {
}
}
fn make_absolute(path: PathBuf) -> PathBuf {
if path.is_relative() {
env::current_dir().unwrap().join(path)
} else {
path
}
}
Config {
compile_lib_path: matches.opt_str("compile-lib-path").unwrap(),
run_lib_path: matches.opt_str("run-lib-path").unwrap(),
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
rustc_path: opt_path(matches, "rustc-path"),
rustdoc_path: opt_path(matches, "rustdoc-path"),
python: matches.opt_str("python").unwrap(),

View File

@ -316,7 +316,7 @@ fn run_pretty_test_revision(config: &Config,
testpaths,
pretty_type.to_owned()),
props.exec_env.clone(),
&config.compile_lib_path,
config.compile_lib_path.to_str().unwrap(),
Some(aux_dir.to_str().unwrap()),
Some(src))
}
@ -635,7 +635,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testpaths: &TestPa
testpaths,
proc_args,
environment,
&config.run_lib_path,
config.run_lib_path.to_str().unwrap(),
None,
None);
}
@ -1315,7 +1315,7 @@ fn exec_compiled_test(config: &Config, props: &TestProps,
testpaths,
make_run_args(config, props, testpaths),
env,
&config.run_lib_path,
config.run_lib_path.to_str().unwrap(),
Some(aux_dir.to_str().unwrap()),
None)
}
@ -1387,7 +1387,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
&aux_testpaths,
aux_args,
Vec::new(),
&config.compile_lib_path,
config.compile_lib_path.to_str().unwrap(),
Some(aux_dir.to_str().unwrap()),
None);
if !auxres.status.success() {
@ -1410,7 +1410,7 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
testpaths,
args,
props.rustc_env.clone(),
&config.compile_lib_path,
config.compile_lib_path.to_str().unwrap(),
Some(aux_dir.to_str().unwrap()),
input)
}

View File

@ -166,7 +166,7 @@ impl<'doc> Doc<'doc> {
}
}
pub fn get<'a>(&'a self, tag: usize) -> Doc<'a> {
pub fn get(&self, tag: usize) -> Doc<'doc> {
reader::get_doc(*self, tag)
}
@ -174,7 +174,7 @@ impl<'doc> Doc<'doc> {
self.start == self.end
}
pub fn as_str_slice<'a>(&'a self) -> &'a str {
pub fn as_str_slice(&self) -> &'doc str {
str::from_utf8(&self.data[self.start..self.end]).unwrap()
}

View File

@ -14,7 +14,7 @@ use super::MapEntry::*;
use rustc_front::hir::*;
use rustc_front::util;
use rustc_front::intravisit::{self, Visitor};
use middle::def_id::{CRATE_DEF_INDEX, DefIndex};
use middle::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
use std::iter::repeat;
use syntax::ast::{NodeId, CRATE_NODE_ID, DUMMY_NODE_ID};
use syntax::codemap::Span;
@ -50,6 +50,7 @@ impl<'ast> NodeCollector<'ast> {
parent: &'ast InlinedParent,
parent_node: NodeId,
parent_def_path: DefPath,
parent_def_id: DefId,
map: Vec<MapEntry<'ast>>,
definitions: Definitions)
-> NodeCollector<'ast> {
@ -60,8 +61,14 @@ impl<'ast> NodeCollector<'ast> {
definitions: definitions,
};
assert_eq!(parent_def_path.krate, parent_def_id.krate);
let root_path = Box::new(InlinedRootPath {
data: parent_def_path.data,
def_id: parent_def_id,
});
collector.insert_entry(parent_node, RootInlinedParent(parent));
collector.create_def(parent_node, DefPathData::InlinedRoot(parent_def_path));
collector.create_def(parent_node, DefPathData::InlinedRoot(root_path));
collector
}
@ -126,11 +133,16 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
// Pick the def data. This need not be unique, but the more
// information we encapsulate into
let def_data = match i.node {
ItemDefaultImpl(..) | ItemImpl(..) => DefPathData::Impl(i.name),
ItemEnum(..) | ItemStruct(..) | ItemTrait(..) => DefPathData::Type(i.name),
ItemExternCrate(..) | ItemMod(..) => DefPathData::Mod(i.name),
ItemStatic(..) | ItemConst(..) | ItemFn(..) => DefPathData::Value(i.name),
_ => DefPathData::Misc,
ItemDefaultImpl(..) | ItemImpl(..) =>
DefPathData::Impl,
ItemEnum(..) | ItemStruct(..) | ItemTrait(..) |
ItemExternCrate(..) | ItemMod(..) | ItemForeignMod(..) |
ItemTy(..) =>
DefPathData::TypeNs(i.name),
ItemStatic(..) | ItemConst(..) | ItemFn(..) =>
DefPathData::ValueNs(i.name),
ItemUse(..) =>
DefPathData::Misc,
};
self.insert_def(i.id, NodeItem(i), def_data);
@ -195,7 +207,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
fn visit_foreign_item(&mut self, foreign_item: &'ast ForeignItem) {
self.insert_def(foreign_item.id,
NodeForeignItem(foreign_item),
DefPathData::Value(foreign_item.name));
DefPathData::ValueNs(foreign_item.name));
let parent_node = self.parent_node;
self.parent_node = foreign_item.id;
@ -215,8 +227,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
fn visit_trait_item(&mut self, ti: &'ast TraitItem) {
let def_data = match ti.node {
MethodTraitItem(..) | ConstTraitItem(..) => DefPathData::Value(ti.name),
TypeTraitItem(..) => DefPathData::Type(ti.name),
MethodTraitItem(..) | ConstTraitItem(..) => DefPathData::ValueNs(ti.name),
TypeTraitItem(..) => DefPathData::TypeNs(ti.name),
};
self.insert(ti.id, NodeTraitItem(ti));
@ -239,8 +251,8 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> {
fn visit_impl_item(&mut self, ii: &'ast ImplItem) {
let def_data = match ii.node {
ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::Value(ii.name),
ImplItemKind::Type(..) => DefPathData::Type(ii.name),
ImplItemKind::Method(..) | ImplItemKind::Const(..) => DefPathData::ValueNs(ii.name),
ImplItemKind::Type(..) => DefPathData::TypeNs(ii.name),
};
self.insert_def(ii.id, NodeImplItem(ii), def_data);

View File

@ -59,23 +59,94 @@ pub struct DefData {
pub node_id: ast::NodeId,
}
pub type DefPath = Vec<DisambiguatedDefPathData>;
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct DefPath {
/// the path leading from the crate root to the item
pub data: Vec<DisambiguatedDefPathData>,
/// what krate root is this path relative to?
pub krate: ast::CrateNum,
}
impl DefPath {
pub fn is_local(&self) -> bool {
self.krate == LOCAL_CRATE
}
pub fn make<FN>(start_krate: ast::CrateNum,
start_index: DefIndex,
mut get_key: FN) -> DefPath
where FN: FnMut(DefIndex) -> DefKey
{
let mut krate = start_krate;
let mut data = vec![];
let mut index = Some(start_index);
loop {
let p = index.unwrap();
let key = get_key(p);
match key.disambiguated_data.data {
DefPathData::CrateRoot => {
assert!(key.parent.is_none());
break;
}
DefPathData::InlinedRoot(ref p) => {
assert!(key.parent.is_none());
assert!(!p.def_id.is_local());
data.extend(p.data.iter().cloned().rev());
krate = p.def_id.krate;
break;
}
_ => {
data.push(key.disambiguated_data);
index = key.parent;
}
}
}
data.reverse();
DefPath { data: data, krate: krate }
}
}
/// Root of an inlined item. We track the `DefPath` of the item within
/// the original crate but also its def-id. This is kind of an
/// augmented version of a `DefPath` that includes a `DefId`. This is
/// all sort of ugly but the hope is that inlined items will be going
/// away soon anyway.
///
/// Some of the constraints that led to the current approach:
///
/// - I don't want to have a `DefId` in the main `DefPath` because
/// that gets serialized for incr. comp., and when reloaded the
/// `DefId` is no longer valid. I'd rather maintain the invariant
/// that every `DefId` is valid, and a potentially outdated `DefId` is
/// represented as a `DefPath`.
/// - (We don't serialize def-paths from inlined items, so it's ok to have one here.)
/// - We need to be able to extract the def-id from inline items to
/// make the symbol name. In theory we could retrace it from the
/// data, but the metadata doesn't have the required indices, and I
/// don't want to write the code to create one just for this.
/// - It may be that we don't actually need `data` at all. We'll have
/// to see about that.
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct InlinedRootPath {
pub data: Vec<DisambiguatedDefPathData>,
pub def_id: DefId,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum DefPathData {
// Root: these should only be used for the root nodes, because
// they are treated specially by the `def_path` function.
CrateRoot,
InlinedRoot(DefPath),
InlinedRoot(Box<InlinedRootPath>),
// Catch-all for random DefId things like DUMMY_NODE_ID
Misc,
// Different kinds of items and item-like things:
Impl(ast::Name),
Type(ast::Name),
Mod(ast::Name),
Value(ast::Name),
Impl,
TypeNs(ast::Name), // something in the type NS
ValueNs(ast::Name), // something in the value NS
MacroDef(ast::Name),
ClosureExpr,
@ -87,10 +158,6 @@ pub enum DefPathData {
StructCtor, // implicit ctor for a tuple-like struct
Initializer, // initializer for a const
Binding(ast::Name), // pattern binding
// An external crate that does not have an `extern crate` in this
// crate.
DetachedCrate(ast::Name),
}
impl Definitions {
@ -116,7 +183,7 @@ impl Definitions {
/// will be the path of the item in the external crate (but the
/// path will begin with the path to the external crate).
pub fn def_path(&self, index: DefIndex) -> DefPath {
make_def_path(index, |p| self.def_key(p))
DefPath::make(LOCAL_CRATE, index, |p| self.def_key(p))
}
pub fn opt_def_index(&self, node: ast::NodeId) -> Option<DefIndex> {
@ -175,20 +242,21 @@ impl DefPathData {
pub fn as_interned_str(&self) -> InternedString {
use self::DefPathData::*;
match *self {
Impl(name) |
Type(name) |
Mod(name) |
Value(name) |
TypeNs(name) |
ValueNs(name) |
MacroDef(name) |
TypeParam(name) |
LifetimeDef(name) |
EnumVariant(name) |
DetachedCrate(name) |
Binding(name) |
Field(name) => {
name.as_str()
}
Impl => {
InternedString::new("{{impl}}")
}
// note that this does not show up in user printouts
CrateRoot => {
InternedString::new("{{root}}")
@ -222,29 +290,3 @@ impl DefPathData {
}
}
pub fn make_def_path<FN>(start_index: DefIndex, mut get_key: FN) -> DefPath
where FN: FnMut(DefIndex) -> DefKey
{
let mut result = vec![];
let mut index = Some(start_index);
while let Some(p) = index {
let key = get_key(p);
match key.disambiguated_data.data {
DefPathData::CrateRoot => {
assert!(key.parent.is_none());
break;
}
DefPathData::InlinedRoot(ref p) => {
assert!(key.parent.is_none());
result.extend(p.iter().cloned().rev());
break;
}
_ => {
result.push(key.disambiguated_data);
index = key.parent;
}
}
}
result.reverse();
result
}

View File

@ -12,13 +12,14 @@ pub use self::Node::*;
pub use self::PathElem::*;
use self::MapEntry::*;
use self::collector::NodeCollector;
pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData};
pub use self::definitions::{Definitions, DefKey, DefPath, DefPathData,
DisambiguatedDefPathData, InlinedRootPath};
use dep_graph::{DepGraph, DepNode};
use middle::cstore::InlinedItem;
use middle::cstore::InlinedItem as II;
use middle::def_id::DefId;
use middle::def_id::{CRATE_DEF_INDEX, DefId};
use syntax::abi::Abi;
use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID};
@ -322,7 +323,8 @@ impl<'ast> Map<'ast> {
id = p,
RootCrate |
RootInlinedParent(_) => // FIXME(#2369) clarify story about cross-crate dep tracking
RootInlinedParent(_) =>
// FIXME(#32015) clarify story about cross-crate dep tracking
return DepNode::Krate,
NotPresent =>
@ -386,6 +388,15 @@ impl<'ast> Map<'ast> {
self.forest.krate()
}
/// Get the attributes on the krate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.
pub fn krate_attrs(&self) -> &'ast [ast::Attribute] {
let crate_root_def_id = DefId::local(CRATE_DEF_INDEX);
self.dep_graph.read(DepNode::Hir(crate_root_def_id));
&self.forest.krate.attrs
}
/// Retrieve the Node corresponding to `id`, panicking if it cannot
/// be found.
pub fn get(&self, id: NodeId) -> Node<'ast> {
@ -958,6 +969,7 @@ pub fn map_crate<'ast>(forest: &'ast mut Forest) -> Map<'ast> {
pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
parent_path: Vec<PathElem>,
parent_def_path: DefPath,
parent_def_id: DefId,
ii: InlinedItem,
fold_ops: F)
-> &'ast InlinedItem {
@ -987,6 +999,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>,
ii_parent,
ii_parent_id,
parent_def_path,
parent_def_id,
mem::replace(&mut *map.map.borrow_mut(), vec![]),
mem::replace(&mut *map.definitions.borrow_mut(), Definitions::new()));
ii_parent.ii.visit(&mut collector);

View File

@ -42,6 +42,7 @@ use syntax::ast_util::{IdVisitingOperation};
use syntax::attr;
use syntax::codemap::Span;
use syntax::ptr::P;
use syntax::parse::token::InternedString;
use rustc_back::target::Target;
use rustc_front::hir;
use rustc_front::intravisit::Visitor;
@ -126,6 +127,27 @@ pub enum FoundAst<'ast> {
NotFound,
}
#[derive(Copy, Clone, Debug)]
pub struct ExternCrate {
/// def_id of an `extern crate` in the current crate that caused
/// this crate to be loaded; note that there could be multiple
/// such ids
pub def_id: DefId,
/// span of the extern crate that caused this to be loaded
pub span: Span,
/// If true, then this crate is the crate named by the extern
/// crate referenced above. If false, then this crate is a dep
/// of the crate.
pub direct: bool,
/// Number of links to reach the extern crate `def_id`
/// declaration; used to select the extern crate with the shortest
/// path
pub path_len: usize,
}
/// A store of Rust crates, through with their metadata
/// can be accessed.
///
@ -146,7 +168,7 @@ pub trait CrateStore<'tcx> : Any {
fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr>;
fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> ty::TypeScheme<'tcx>;
fn item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem>;
fn item_name(&self, def: DefId) -> ast::Name;
fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId)
@ -202,9 +224,15 @@ pub trait CrateStore<'tcx> : Any {
fn is_staged_api(&self, cnum: ast::CrateNum) -> bool;
fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool;
fn is_allocator(&self, cnum: ast::CrateNum) -> bool;
fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate>;
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>;
fn crate_name(&self, cnum: ast::CrateNum) -> String;
/// The name of the crate as it is referred to in source code of the current
/// crate.
fn crate_name(&self, cnum: ast::CrateNum) -> InternedString;
/// The name of the crate as it is stored in the crate's metadata.
fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString;
fn crate_hash(&self, cnum: ast::CrateNum) -> Svh;
fn crate_disambiguator(&self, cnum: ast::CrateNum) -> InternedString;
fn crate_struct_field_attrs(&self, cnum: ast::CrateNum)
-> FnvHashMap<DefId, Vec<ast::Attribute>>;
fn plugin_registrar_fn(&self, cnum: ast::CrateNum) -> Option<DefId>;
@ -212,7 +240,8 @@ pub trait CrateStore<'tcx> : Any {
fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId>;
// resolve
fn def_path(&self, def: DefId) -> hir_map::DefPath;
fn def_key(&self, def: DefId) -> hir_map::DefKey;
fn relative_def_path(&self, def: DefId) -> hir_map::DefPath;
fn variant_kind(&self, def_id: DefId) -> Option<VariantKind>;
fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>;
fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>;
@ -236,7 +265,11 @@ pub trait CrateStore<'tcx> : Any {
// utility functions
fn metadata_filename(&self) -> &str;
fn metadata_section_name(&self, target: &Target) -> &str;
fn encode_type(&self, tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<u8>;
fn encode_type(&self,
tcx: &TyCtxt<'tcx>,
ty: Ty<'tcx>,
def_id_to_string: fn(&TyCtxt<'tcx>, DefId) -> String)
-> Vec<u8>;
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option<PathBuf>)>;
fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource;
fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<ast::CrateNum>;
@ -313,7 +346,7 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> { unimplemented!() }
fn item_type(&self, tcx: &TyCtxt<'tcx>, def: DefId)
-> ty::TypeScheme<'tcx> { unimplemented!() }
fn item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { unimplemented!() }
fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { unimplemented!() }
fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> { unimplemented!() }
fn item_name(&self, def: DefId) -> ast::Name { unimplemented!() }
fn item_predicates(&self, tcx: &TyCtxt<'tcx>, def: DefId)
@ -376,10 +409,15 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
fn is_staged_api(&self, cnum: ast::CrateNum) -> bool { unimplemented!() }
fn is_explicitly_linked(&self, cnum: ast::CrateNum) -> bool { unimplemented!() }
fn is_allocator(&self, cnum: ast::CrateNum) -> bool { unimplemented!() }
fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate> { unimplemented!() }
fn crate_attrs(&self, cnum: ast::CrateNum) -> Vec<ast::Attribute>
{ unimplemented!() }
fn crate_name(&self, cnum: ast::CrateNum) -> String { unimplemented!() }
fn crate_name(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() }
fn original_crate_name(&self, cnum: ast::CrateNum) -> InternedString {
unimplemented!()
}
fn crate_hash(&self, cnum: ast::CrateNum) -> Svh { unimplemented!() }
fn crate_disambiguator(&self, cnum: ast::CrateNum) -> InternedString { unimplemented!() }
fn crate_struct_field_attrs(&self, cnum: ast::CrateNum)
-> FnvHashMap<DefId, Vec<ast::Attribute>>
{ unimplemented!() }
@ -390,7 +428,8 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId> { unimplemented!() }
// resolve
fn def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() }
fn def_key(&self, def: DefId) -> hir_map::DefKey { unimplemented!() }
fn relative_def_path(&self, def: DefId) -> hir_map::DefPath { unimplemented!() }
fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> { unimplemented!() }
fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>
{ unimplemented!() }
@ -419,8 +458,13 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
// utility functions
fn metadata_filename(&self) -> &str { unimplemented!() }
fn metadata_section_name(&self, target: &Target) -> &str { unimplemented!() }
fn encode_type(&self, tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<u8>
{ unimplemented!() }
fn encode_type(&self,
tcx: &TyCtxt<'tcx>,
ty: Ty<'tcx>,
def_id_to_string: fn(&TyCtxt<'tcx>, DefId) -> String)
-> Vec<u8> {
unimplemented!()
}
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option<PathBuf>)>
{ vec![] }
fn used_crate_source(&self, cnum: ast::CrateNum) -> CrateSource { unimplemented!() }

View File

@ -398,7 +398,7 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
// purposes of the ancestor check, we retain
// the invariant that all type variables are
// fully refreshed.
if !(&mut is_ancestor)(&obligation.predicate) {
if !is_ancestor(&obligation.predicate) {
return None;
}
}

View File

@ -15,7 +15,7 @@ use front::map as ast_map;
use session::Session;
use lint;
use middle;
use middle::cstore::CrateStore;
use middle::cstore::{CrateStore, LOCAL_CRATE};
use middle::def::DefMap;
use middle::def_id::DefId;
use middle::free_region::FreeRegionMap;
@ -43,7 +43,7 @@ use std::hash::{Hash, Hasher};
use std::rc::Rc;
use syntax::ast::{self, Name, NodeId};
use syntax::attr;
use syntax::parse::token::special_idents;
use syntax::parse::token::{self, special_idents};
use rustc_front::hir;
@ -415,9 +415,29 @@ pub struct TyCtxt<'tcx> {
/// fragmented data to the set of unfragmented pieces that
/// constitute it.
pub fragment_infos: RefCell<DefIdMap<Vec<ty::FragmentInfo>>>,
/// The definite name of the current crate after taking into account
/// attributes, commandline parameters, etc.
pub crate_name: token::InternedString,
}
impl<'tcx> TyCtxt<'tcx> {
pub fn crate_name(&self, cnum: ast::CrateNum) -> token::InternedString {
if cnum == LOCAL_CRATE {
self.crate_name.clone()
} else {
self.sess.cstore.crate_name(cnum)
}
}
pub fn crate_disambiguator(&self, cnum: ast::CrateNum) -> token::InternedString {
if cnum == LOCAL_CRATE {
self.sess.crate_disambiguator.get().as_str()
} else {
self.sess.cstore.crate_name(cnum)
}
}
pub fn type_parameter_def(&self,
node_id: NodeId)
-> ty::TypeParameterDef<'tcx>
@ -511,6 +531,7 @@ impl<'tcx> TyCtxt<'tcx> {
region_maps: RegionMaps,
lang_items: middle::lang_items::LanguageItems,
stability: stability::Index<'tcx>,
crate_name: &str,
f: F) -> R
where F: FnOnce(&TyCtxt<'tcx>) -> R
{
@ -570,7 +591,8 @@ impl<'tcx> TyCtxt<'tcx> {
const_qualif_map: RefCell::new(NodeMap()),
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
cast_kinds: RefCell::new(NodeMap()),
fragment_infos: RefCell::new(DefIdMap())
fragment_infos: RefCell::new(DefIdMap()),
crate_name: token::intern_and_get_ident(crate_name),
}, f)
}
}

View File

@ -0,0 +1,317 @@
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use front::map::DefPathData;
use middle::cstore::LOCAL_CRATE;
use middle::def_id::DefId;
use middle::ty::{self, Ty, TyCtxt};
use syntax::ast;
impl<'tcx> TyCtxt<'tcx> {
/// Returns a string identifying this def-id. This string is
/// suitable for user output. It is relative to the current crate
/// root.
pub fn item_path_str(&self, def_id: DefId) -> String {
let mut buffer = LocalPathBuffer::new(RootMode::Local);
self.push_item_path(&mut buffer, def_id);
buffer.into_string()
}
/// Returns a string identifying this def-id. This string is
/// suitable for user output. It always begins with a crate identifier.
pub fn absolute_item_path_str(&self, def_id: DefId) -> String {
let mut buffer = LocalPathBuffer::new(RootMode::Absolute);
self.push_item_path(&mut buffer, def_id);
buffer.into_string()
}
/// Returns the "path" to a particular crate. This can proceed in
/// various ways, depending on the `root_mode` of the `buffer`.
/// (See `RootMode` enum for more details.)
pub fn push_krate_path<T>(&self, buffer: &mut T, cnum: ast::CrateNum)
where T: ItemPathBuffer
{
match *buffer.root_mode() {
RootMode::Local => {
// In local mode, when we encounter a crate other than
// LOCAL_CRATE, execution proceeds in one of two ways:
//
// 1. for a direct dependency, where user added an
// `extern crate` manually, we put the `extern
// crate` as the parent. So you wind up with
// something relative to the current crate.
// 2. for an indirect crate, where there is no extern
// crate, we just prepend the crate name.
//
// Returns `None` for the local crate.
if cnum != LOCAL_CRATE {
let opt_extern_crate = self.sess.cstore.extern_crate(cnum);
let opt_extern_crate = opt_extern_crate.and_then(|extern_crate| {
if extern_crate.direct {
Some(extern_crate.def_id)
} else {
None
}
});
if let Some(extern_crate_def_id) = opt_extern_crate {
self.push_item_path(buffer, extern_crate_def_id);
} else {
buffer.push(&self.crate_name(cnum));
}
}
}
RootMode::Absolute => {
// In absolute mode, just write the crate name
// unconditionally.
buffer.push(&self.crate_name(cnum));
}
}
}
pub fn push_item_path<T>(&self, buffer: &mut T, def_id: DefId)
where T: ItemPathBuffer
{
let key = self.def_key(def_id);
match key.disambiguated_data.data {
DefPathData::CrateRoot => {
assert!(key.parent.is_none());
self.push_krate_path(buffer, def_id.krate);
}
DefPathData::InlinedRoot(ref root_path) => {
assert!(key.parent.is_none());
self.push_item_path(buffer, root_path.def_id);
}
DefPathData::Impl => {
self.push_impl_path(buffer, def_id);
}
// Unclear if there is any value in distinguishing these.
// Probably eventually (and maybe we would even want
// finer-grained distinctions, e.g. between enum/struct).
data @ DefPathData::Misc |
data @ DefPathData::TypeNs(..) |
data @ DefPathData::ValueNs(..) |
data @ DefPathData::TypeParam(..) |
data @ DefPathData::LifetimeDef(..) |
data @ DefPathData::EnumVariant(..) |
data @ DefPathData::Field(..) |
data @ DefPathData::StructCtor |
data @ DefPathData::Initializer |
data @ DefPathData::MacroDef(..) |
data @ DefPathData::ClosureExpr |
data @ DefPathData::Binding(..) => {
let parent_def_id = self.parent_def_id(def_id).unwrap();
self.push_item_path(buffer, parent_def_id);
buffer.push(&data.as_interned_str());
}
}
}
fn push_impl_path<T>(&self,
buffer: &mut T,
impl_def_id: DefId)
where T: ItemPathBuffer
{
let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
let use_types = if !impl_def_id.is_local() {
// always have full types available for extern crates
true
} else {
// for local crates, check whether type info is
// available; typeck might not have completed yet
self.impl_trait_refs.borrow().contains_key(&impl_def_id)
};
if !use_types {
return self.push_impl_path_fallback(buffer, impl_def_id);
}
// Decide whether to print the parent path for the impl.
// Logically, since impls are global, it's never needed, but
// users may find it useful. Currently, we omit the parent if
// the impl is either in the same module as the self-type or
// as the trait.
let self_ty = self.lookup_item_type(impl_def_id).ty;
let in_self_mod = match self.characteristic_def_id_of_type(self_ty) {
None => false,
Some(ty_def_id) => self.parent_def_id(ty_def_id) == Some(parent_def_id),
};
let impl_trait_ref = self.impl_trait_ref(impl_def_id);
let in_trait_mod = match impl_trait_ref {
None => false,
Some(trait_ref) => self.parent_def_id(trait_ref.def_id) == Some(parent_def_id),
};
if !in_self_mod && !in_trait_mod {
// If the impl is not co-located with either self-type or
// trait-type, then fallback to a format that identifies
// the module more clearly.
self.push_item_path(buffer, parent_def_id);
if let Some(trait_ref) = impl_trait_ref {
buffer.push(&format!("<impl {} for {}>", trait_ref, self_ty));
} else {
buffer.push(&format!("<impl {}>", self_ty));
}
return;
}
// Otherwise, try to give a good form that would be valid language
// syntax. Preferably using associated item notation.
if let Some(trait_ref) = impl_trait_ref {
// Trait impls.
buffer.push(&format!("<{} as {}>",
self_ty,
trait_ref));
return;
}
// Inherent impls. Try to print `Foo::bar` for an inherent
// impl on `Foo`, but fallback to `<Foo>::bar` if self-type is
// anything other than a simple path.
match self_ty.sty {
ty::TyStruct(adt_def, substs) |
ty::TyEnum(adt_def, substs) => {
if substs.types.is_empty() { // ignore regions
self.push_item_path(buffer, adt_def.did);
} else {
buffer.push(&format!("<{}>", self_ty));
}
}
ty::TyBool |
ty::TyChar |
ty::TyInt(_) |
ty::TyUint(_) |
ty::TyFloat(_) |
ty::TyStr => {
buffer.push(&format!("{}", self_ty));
}
_ => {
buffer.push(&format!("<{}>", self_ty));
}
}
}
fn push_impl_path_fallback<T>(&self,
buffer: &mut T,
impl_def_id: DefId)
where T: ItemPathBuffer
{
// If no type info is available, fall back to
// pretty printing some span information. This should
// only occur very early in the compiler pipeline.
let parent_def_id = self.parent_def_id(impl_def_id).unwrap();
self.push_item_path(buffer, parent_def_id);
let node_id = self.map.as_local_node_id(impl_def_id).unwrap();
let item = self.map.expect_item(node_id);
let span_str = self.sess.codemap().span_to_string(item.span);
buffer.push(&format!("<impl at {}>", span_str));
}
/// As a heuristic, when we see an impl, if we see that the
/// 'self-type' is a type defined in the same module as the impl,
/// we can omit including the path to the impl itself. This
/// function tries to find a "characteristic def-id" for a
/// type. It's just a heuristic so it makes some questionable
/// decisions and we may want to adjust it later.
fn characteristic_def_id_of_type(&self, ty: Ty<'tcx>) -> Option<DefId> {
match ty.sty {
ty::TyStruct(adt_def, _) |
ty::TyEnum(adt_def, _) =>
Some(adt_def.did),
ty::TyTrait(ref data) =>
Some(data.principal_def_id()),
ty::TyBox(subty) =>
self.characteristic_def_id_of_type(subty),
ty::TyRawPtr(mt) |
ty::TyRef(_, mt) =>
self.characteristic_def_id_of_type(mt.ty),
ty::TyTuple(ref tys) =>
tys.iter()
.filter_map(|ty| self.characteristic_def_id_of_type(ty))
.next(),
_ =>
None
}
}
/// Returns the def-id of `def_id`'s parent in the def tree. If
/// this returns `None`, then `def_id` represents a crate root or
/// inlined root.
fn parent_def_id(&self, def_id: DefId) -> Option<DefId> {
let key = self.def_key(def_id);
key.parent.map(|index| DefId { krate: def_id.krate, index: index })
}
}
/// Unifying Trait for different kinds of item paths we might
/// construct. The basic interface is that components get pushed: the
/// instance can also customize how we handle the root of a crate.
pub trait ItemPathBuffer {
fn root_mode(&self) -> &RootMode;
fn push(&mut self, text: &str);
}
#[derive(Debug)]
pub enum RootMode {
/// Try to make a path relative to the local crate. In
/// particular, local paths have no prefix, and if the path comes
/// from an extern crate, start with the path to the `extern
/// crate` declaration.
Local,
/// Always prepend the crate name to the path, forming an absolute
/// path from within a given set of crates.
Absolute,
}
#[derive(Debug)]
struct LocalPathBuffer {
root_mode: RootMode,
str: String,
}
impl LocalPathBuffer {
fn new(root_mode: RootMode) -> LocalPathBuffer {
LocalPathBuffer {
root_mode: root_mode,
str: String::new()
}
}
fn into_string(self) -> String {
self.str
}
}
impl ItemPathBuffer for LocalPathBuffer {
fn root_mode(&self) -> &RootMode {
&self.root_mode
}
fn push(&mut self, text: &str) {
if !self.str.is_empty() {
self.str.push_str("::");
}
self.str.push_str(text);
}
}

View File

@ -86,6 +86,7 @@ pub mod cast;
pub mod error;
pub mod fast_reject;
pub mod fold;
pub mod item_path;
pub mod _match;
pub mod maps;
pub mod outlives;
@ -2218,15 +2219,22 @@ impl<'tcx> TyCtxt<'tcx> {
self.def_map.borrow().get(&tr.ref_id).expect("no def-map entry for trait").def_id()
}
pub fn item_path_str(&self, id: DefId) -> String {
self.with_path(id, |path| ast_map::path_to_string(path))
pub fn def_key(&self, id: DefId) -> ast_map::DefKey {
if id.is_local() {
self.map.def_key(id)
} else {
self.sess.cstore.def_key(id)
}
}
/// Returns the `DefPath` of an item. Note that if `id` is not
/// local to this crate -- or is inlined into this crate -- the
/// result will be a non-local `DefPath`.
pub fn def_path(&self, id: DefId) -> ast_map::DefPath {
if id.is_local() {
self.map.def_path(id)
} else {
self.sess.cstore.def_path(id)
self.sess.cstore.relative_def_path(id)
}
}
@ -2236,7 +2244,27 @@ impl<'tcx> TyCtxt<'tcx> {
if let Some(id) = self.map.as_local_node_id(id) {
self.map.with_path(id, f)
} else {
f(self.sess.cstore.item_path(id).iter().cloned().chain(LinkedPath::empty()))
let mut path: Vec<_>;
if let Some(extern_crate) = self.sess.cstore.extern_crate(id.krate) {
if !extern_crate.direct {
// this comes from some crate that we don't have a direct
// path to; we'll settle for just prepending the name of
// the crate.
path = self.sess.cstore.extern_item_path(id)
} else {
// start with the path to the extern crate, then
// add the relative path to the actual item
fn collector(elems: ast_map::PathElems) -> Vec<ast_map::PathElem> {
elems.collect()
}
path = self.with_path(extern_crate.def_id, collector);
path.extend(self.sess.cstore.relative_item_path(id));
}
} else {
// if this was injected, just make a path with name of crate
path = self.sess.cstore.extern_item_path(id);
}
f(path.iter().cloned().chain(LinkedPath::empty()))
}
}
@ -2680,9 +2708,10 @@ impl<'tcx> TyCtxt<'tcx> {
{
dep_graph::visit_all_items_in_krate(self, dep_node_fn, visitor);
}
/// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
/// with the name of the crate containing the impl.
pub fn span_of_impl(&self, impl_did: DefId) -> Result<Span, String> {
pub fn span_of_impl(&self, impl_did: DefId) -> Result<Span, InternedString> {
if impl_did.is_local() {
let node_id = self.map.as_local_node_id(impl_did).unwrap();
Ok(self.map.span(node_id))

View File

@ -24,6 +24,7 @@ use syntax::diagnostics;
use syntax::feature_gate;
use syntax::parse;
use syntax::parse::ParseSess;
use syntax::parse::token;
use syntax::{ast, codemap};
use syntax::feature_gate::AttributeType;
@ -64,7 +65,12 @@ pub struct Session {
pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
pub crate_types: RefCell<Vec<config::CrateType>>,
pub dependency_formats: RefCell<dependency_format::Dependencies>,
pub crate_metadata: RefCell<Vec<String>>,
// The crate_disambiguator is constructed out of all the `-C metadata`
// arguments passed to the compiler. Its value together with the crate-name
// forms a unique global identifier for the crate. It is used to allow
// multiple crates with the same name to coexist. See the
// trans::back::symbol_names module for more information.
pub crate_disambiguator: Cell<ast::Name>,
pub features: RefCell<feature_gate::Features>,
/// The maximum recursion limit for potentially infinitely recursive
@ -481,7 +487,7 @@ pub fn build_session_(sopts: config::Options,
plugin_attributes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
dependency_formats: RefCell::new(FnvHashMap()),
crate_metadata: RefCell::new(Vec::new()),
crate_disambiguator: Cell::new(token::intern("")),
features: RefCell::new(feature_gate::Features::new()),
recursion_limit: Cell::new(64),
next_node_id: Cell::new(1),

View File

@ -66,7 +66,7 @@ impl Svh {
&self.hash
}
pub fn calculate(metadata: &Vec<String>, krate: &hir::Crate) -> Svh {
pub fn calculate(crate_disambiguator: &str, krate: &hir::Crate) -> Svh {
// FIXME (#14132): This is better than it used to be, but it still not
// ideal. We now attempt to hash only the relevant portions of the
// Crate AST as well as the top-level crate attributes. (However,
@ -78,9 +78,9 @@ impl Svh {
// avoid collisions.
let mut state = SipHasher::new();
for data in metadata {
data.hash(&mut state);
}
"crate_disambiguator".hash(&mut state);
crate_disambiguator.len().hash(&mut state);
crate_disambiguator.hash(&mut state);
{
let mut visit = svh_visitor::make(&mut state, krate);

View File

@ -22,6 +22,7 @@ use rustc::middle::privacy::AccessLevels;
use rustc::middle::ty::TyCtxt;
use rustc::util::common::time;
use rustc::util::nodemap::NodeSet;
use rustc_back::sha2::{Sha256, Digest};
use rustc_borrowck as borrowck;
use rustc_resolve as resolve;
use rustc_metadata::macro_import;
@ -500,7 +501,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
})?;
*sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
*sess.crate_metadata.borrow_mut() = collect_crate_metadata(sess, &krate.attrs);
sess.crate_disambiguator.set(token::intern(&compute_crate_disambiguator(sess)));
time(time_passes, "recursion limit", || {
middle::recursion_limit::update_recursion_limit(sess, &krate);
@ -525,11 +526,15 @@ pub fn phase_2_configure_and_expand(sess: &Session,
let macros = time(time_passes,
"macro loading",
|| macro_import::read_macro_defs(sess, &cstore, &krate));
|| macro_import::read_macro_defs(sess, &cstore, &krate, crate_name));
let mut addl_plugins = Some(addl_plugins);
let registrars = time(time_passes, "plugin loading", || {
plugin::load::load_plugins(sess, &cstore, &krate, addl_plugins.take().unwrap())
plugin::load::load_plugins(sess,
&cstore,
&krate,
crate_name,
addl_plugins.take().unwrap())
});
let mut registry = Registry::new(sess, &krate);
@ -754,7 +759,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
time(time_passes,
"external crate/lib resolution",
|| LocalCrateReader::new(sess, cstore, &hir_map).read_crates());
|| LocalCrateReader::new(sess, cstore, &hir_map, name).read_crates());
let lang_items = time(time_passes, "language item collection", || {
sess.track_errors(|| {
@ -817,6 +822,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
region_map,
lang_items,
index,
name,
|tcx| {
// passes are timed inside typeck
try_with_f!(typeck::check_crate(tcx, trait_map), (tcx, None, analysis));
@ -1121,8 +1127,34 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
.collect()
}
pub fn collect_crate_metadata(session: &Session, _attrs: &[ast::Attribute]) -> Vec<String> {
session.opts.cg.metadata.clone()
pub fn compute_crate_disambiguator(session: &Session) -> String {
let mut hasher = Sha256::new();
let mut metadata = session.opts.cg.metadata.clone();
// We don't want the crate_disambiguator to dependent on the order
// -C metadata arguments, so sort them:
metadata.sort();
// Every distinct -C metadata value is only incorporated once:
metadata.dedup();
hasher.input_str("metadata");
for s in &metadata {
// Also incorporate the length of a metadata string, so that we generate
// different values for `-Cmetadata=ab -Cmetadata=c` and
// `-Cmetadata=a -Cmetadata=bc`
hasher.input_str(&format!("{}", s.len())[..]);
hasher.input_str(&s[..]);
}
let mut hash = hasher.result_str();
// If this is an executable, add a special suffix, so that we don't get
// symbol conflicts when linking against a library of the same name.
if session.crate_types.borrow().contains(&config::CrateTypeExecutable) {
hash.push_str("-exe");
}
hash
}
pub fn build_output_filenames(input: &Input,

View File

@ -568,8 +568,6 @@ impl RustcDefaultCalls {
continue;
}
let crate_types = driver::collect_crate_types(sess, attrs);
let metadata = driver::collect_crate_metadata(sess, attrs);
*sess.crate_metadata.borrow_mut() = metadata;
for &style in &crate_types {
let fname = link::filename_for_input(sess, style, &id, &t_outputs);
println!("{}",

View File

@ -146,6 +146,7 @@ fn test_env<F>(source_string: &str,
region_map,
lang_items,
index,
"test_crate",
|tcx| {
let infcx = infer::new_infer_ctxt(tcx,
&tcx.tables,

View File

@ -125,6 +125,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
tcx: &TyCtxt<'tcx>,
parent_path: Vec<ast_map::PathElem>,
parent_def_path: ast_map::DefPath,
parent_did: DefId,
ast_doc: rbml::Doc,
orig_did: DefId)
-> &'tcx InlinedItem {
@ -149,6 +150,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata,
let ii = ast_map::map_decoded_item(&dcx.tcx.map,
parent_path,
parent_def_path,
parent_did,
decode_ast(ast_doc),
dcx);
let name = match *ii {
@ -349,8 +351,8 @@ fn simplify_ast(ii: InlinedItemRef) -> InlinedItem {
}
}
fn decode_ast(par_doc: rbml::Doc) -> InlinedItem {
let chi_doc = par_doc.get(c::tag_tree as usize);
fn decode_ast(item_doc: rbml::Doc) -> InlinedItem {
let chi_doc = item_doc.get(c::tag_tree as usize);
let mut rbml_r = reader::Decoder::new(chi_doc);
rbml_r.read_opaque(|decoder, _| Decodable::decode(decoder)).unwrap()
}
@ -1280,8 +1282,8 @@ fn encode_item_ast(rbml_w: &mut Encoder, item: &hir::Item) {
}
#[cfg(test)]
fn decode_item_ast(par_doc: rbml::Doc) -> hir::Item {
let chi_doc = par_doc.get(c::tag_tree as usize);
fn decode_item_ast(item_doc: rbml::Doc) -> hir::Item {
let chi_doc = item_doc.get(c::tag_tree as usize);
let mut d = reader::Decoder::new(chi_doc);
Decodable::decode(&mut d).unwrap()
}

View File

@ -73,6 +73,7 @@ pub const tag_crate_dep: usize = 0x35;
pub const tag_crate_hash: usize = 0x103; // top-level only
pub const tag_crate_crate_name: usize = 0x104; // top-level only
pub const tag_crate_disambiguator: usize = 0x113; // top-level only
pub const tag_crate_dep_crate_name: usize = 0x36;
pub const tag_crate_dep_hash: usize = 0x37;

View File

@ -21,7 +21,7 @@ use rustc::back::svh::Svh;
use rustc::dep_graph::DepNode;
use rustc::session::{config, Session};
use rustc::session::search_paths::PathKind;
use rustc::middle::cstore::{CrateStore, validate_crate_name};
use rustc::middle::cstore::{CrateStore, validate_crate_name, ExternCrate};
use rustc::util::nodemap::FnvHashMap;
use rustc::front::map as hir_map;
@ -38,7 +38,6 @@ use syntax::attr;
use syntax::attr::AttrMetaMethods;
use syntax::errors::FatalError;
use syntax::parse::token::InternedString;
use syntax::util::small_vector::SmallVector;
use rustc_front::intravisit::Visitor;
use rustc_front::hir;
use log;
@ -55,6 +54,7 @@ pub struct CrateReader<'a> {
cstore: &'a CStore,
next_crate_num: ast::CrateNum,
foreign_item_map: FnvHashMap<String, Vec<ast::NodeId>>,
local_crate_name: String,
}
impl<'a, 'b, 'hir> Visitor<'hir> for LocalCrateReader<'a, 'b> {
@ -146,12 +146,15 @@ impl PMDSource {
}
impl<'a> CrateReader<'a> {
pub fn new(sess: &'a Session, cstore: &'a CStore) -> CrateReader<'a> {
pub fn new(sess: &'a Session,
cstore: &'a CStore,
local_crate_name: &str) -> CrateReader<'a> {
CrateReader {
sess: sess,
cstore: cstore,
next_crate_num: cstore.next_crate_num(),
foreign_item_map: FnvHashMap(),
local_crate_name: local_crate_name.to_owned(),
}
}
@ -272,6 +275,38 @@ impl<'a> CrateReader<'a> {
}
}
fn verify_no_symbol_conflicts(&self,
span: Span,
metadata: &MetadataBlob) {
let disambiguator = decoder::get_crate_disambiguator(metadata.as_slice());
let crate_name = decoder::get_crate_name(metadata.as_slice());
// Check for (potential) conflicts with the local crate
if self.local_crate_name == crate_name &&
self.sess.crate_disambiguator.get().as_str() == disambiguator {
span_fatal!(self.sess, span, E0519,
"the current crate is indistinguishable from one of its \
dependencies: it has the same crate-name `{}` and was \
compiled with the same `-C metadata` arguments. This \
will result in symbol conflicts between the two.",
crate_name)
}
let svh = decoder::get_crate_hash(metadata.as_slice());
// Check for conflicts with any crate loaded so far
self.cstore.iter_crate_data(|_, other| {
if other.name() == crate_name && // same crate-name
other.disambiguator() == disambiguator && // same crate-disambiguator
other.hash() != svh { // but different SVH
span_fatal!(self.sess, span, E0523,
"found two different crates with name `{}` that are \
not distinguished by differing `-C metadata`. This \
will result in symbol conflicts between the two.",
crate_name)
}
});
}
fn register_crate(&mut self,
root: &Option<CratePaths>,
ident: &str,
@ -282,6 +317,7 @@ impl<'a> CrateReader<'a> {
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
cstore::CrateSource) {
self.verify_rustc_version(name, span, &lib.metadata);
self.verify_no_symbol_conflicts(span, &lib.metadata);
// Claim this crate number and cache it
let cnum = self.next_crate_num;
@ -307,15 +343,13 @@ impl<'a> CrateReader<'a> {
let cmeta = Rc::new(cstore::crate_metadata {
name: name.to_string(),
local_path: RefCell::new(SmallVector::zero()),
local_def_path: RefCell::new(vec![]),
extern_crate: Cell::new(None),
index: decoder::load_index(metadata.as_slice()),
xref_index: decoder::load_xrefs(metadata.as_slice()),
data: metadata,
cnum_map: RefCell::new(cnum_map),
cnum: cnum,
codemap_import_info: RefCell::new(vec![]),
span: span,
staged_api: staged_api,
explicitly_linked: Cell::new(explicitly_linked),
});
@ -349,8 +383,7 @@ impl<'a> CrateReader<'a> {
span: Span,
kind: PathKind,
explicitly_linked: bool)
-> (ast::CrateNum, Rc<cstore::crate_metadata>,
cstore::CrateSource) {
-> (ast::CrateNum, Rc<cstore::crate_metadata>, cstore::CrateSource) {
enum LookupResult {
Previous(ast::CrateNum),
Loaded(loader::Library),
@ -407,23 +440,54 @@ impl<'a> CrateReader<'a> {
}
}
fn update_extern_crate(&mut self,
cnum: ast::CrateNum,
mut extern_crate: ExternCrate)
{
let cmeta = self.cstore.get_crate_data(cnum);
let old_extern_crate = cmeta.extern_crate.get();
// Prefer:
// - something over nothing (tuple.0);
// - direct extern crate to indirect (tuple.1);
// - shorter paths to longer (tuple.2).
let new_rank = (true, extern_crate.direct, !extern_crate.path_len);
let old_rank = match old_extern_crate {
None => (false, false, !0),
Some(ref c) => (true, c.direct, !c.path_len),
};
if old_rank >= new_rank {
return; // no change needed
}
cmeta.extern_crate.set(Some(extern_crate));
// Propagate the extern crate info to dependencies.
extern_crate.direct = false;
for &dep_cnum in cmeta.cnum_map.borrow().values() {
self.update_extern_crate(dep_cnum, extern_crate);
}
}
// Go through the crate metadata and load any crates that it references
fn resolve_crate_deps(&mut self,
root: &Option<CratePaths>,
cdata: &[u8], span : Span)
-> cstore::cnum_map {
cdata: &[u8],
span : Span)
-> cstore::cnum_map {
debug!("resolving deps of external crate");
// The map from crate numbers in the crate we're resolving to local crate
// numbers
decoder::get_crate_deps(cdata).iter().map(|dep| {
debug!("resolving dep crate {} hash: `{}`", dep.name, dep.hash);
let (local_cnum, _, _) = self.resolve_crate(root,
&dep.name,
&dep.name,
Some(&dep.hash),
span,
PathKind::Dependency,
dep.explicitly_linked);
&dep.name,
&dep.name,
Some(&dep.hash),
span,
PathKind::Dependency,
dep.explicitly_linked);
(dep.cnum, local_cnum)
}).collect()
}
@ -713,12 +777,15 @@ impl<'a> CrateReader<'a> {
}
impl<'a, 'b> LocalCrateReader<'a, 'b> {
pub fn new(sess: &'a Session, cstore: &'a CStore,
map: &'a hir_map::Map<'b>) -> LocalCrateReader<'a, 'b> {
pub fn new(sess: &'a Session,
cstore: &'a CStore,
map: &'a hir_map::Map<'b>,
local_crate_name: &str)
-> LocalCrateReader<'a, 'b> {
LocalCrateReader {
sess: sess,
cstore: cstore,
creader: CrateReader::new(sess, cstore),
creader: CrateReader::new(sess, cstore, local_crate_name),
ast_map: map,
}
}
@ -762,19 +829,24 @@ impl<'a, 'b> LocalCrateReader<'a, 'b> {
match self.creader.extract_crate_info_hir(i) {
Some(info) => {
let (cnum, cmeta, _) = self.creader.resolve_crate(&None,
&info.ident,
&info.name,
None,
i.span,
PathKind::Crate,
true);
let (cnum, _, _) = self.creader.resolve_crate(&None,
&info.ident,
&info.name,
None,
i.span,
PathKind::Crate,
true);
let def_id = self.ast_map.local_def_id(i.id);
let def_path = self.ast_map.def_path(def_id);
cmeta.update_local_def_path(def_path);
self.ast_map.with_path(i.id, |path| {
cmeta.update_local_path(path)
});
let len = self.ast_map.def_path(def_id).data.len();
self.creader.update_extern_crate(cnum,
ExternCrate {
def_id: def_id,
span: i.span,
direct: true,
path_len: len,
});
self.cstore.add_extern_mod_stmt_cnum(info.id, cnum);
}
None => ()

View File

@ -13,7 +13,7 @@ use decoder;
use encoder;
use loader;
use middle::cstore::{CrateStore, CrateSource, ChildItem, FoundAst};
use middle::cstore::{CrateStore, CrateSource, ChildItem, ExternCrate, FoundAst};
use middle::cstore::{NativeLibraryKind, LinkMeta, LinkagePreference};
use middle::def;
use middle::lang_items;
@ -128,16 +128,9 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
decoder::get_method_arg_names(&cdata, did.index)
}
fn item_path(&self, def: DefId) -> Vec<hir_map::PathElem> {
fn relative_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> {
let cdata = self.get_crate_data(def.krate);
let path = decoder::get_item_path(&cdata, def.index);
cdata.with_local_path(|cpath| {
let mut r = Vec::with_capacity(cpath.len() + path.len());
r.extend_from_slice(cpath);
r.extend_from_slice(&path);
r
})
decoder::get_item_path(&cdata, def.index)
}
fn extern_item_path(&self, def: DefId) -> Vec<hir_map::PathElem> {
@ -334,9 +327,19 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
decoder::get_crate_attributes(self.get_crate_data(cnum).data())
}
fn crate_name(&self, cnum: ast::CrateNum) -> String
fn crate_name(&self, cnum: ast::CrateNum) -> token::InternedString
{
self.get_crate_data(cnum).name.clone()
token::intern_and_get_ident(&self.get_crate_data(cnum).name[..])
}
fn original_crate_name(&self, cnum: ast::CrateNum) -> token::InternedString
{
token::intern_and_get_ident(&self.get_crate_data(cnum).name())
}
fn extern_crate(&self, cnum: ast::CrateNum) -> Option<ExternCrate>
{
self.get_crate_data(cnum).extern_crate.get()
}
fn crate_hash(&self, cnum: ast::CrateNum) -> Svh
@ -345,6 +348,12 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
decoder::get_crate_hash(cdata.data())
}
fn crate_disambiguator(&self, cnum: ast::CrateNum) -> token::InternedString
{
let cdata = self.get_crate_data(cnum);
token::intern_and_get_ident(decoder::get_crate_disambiguator(cdata.data()))
}
fn crate_struct_field_attrs(&self, cnum: ast::CrateNum)
-> FnvHashMap<DefId, Vec<ast::Attribute>>
{
@ -372,12 +381,17 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
decoder::get_reachable_ids(&cdata)
}
fn def_path(&self, def: DefId) -> hir_map::DefPath
{
/// Returns the `DefKey` for a given `DefId`. This indicates the
/// parent `DefId` as well as some idea of what kind of data the
/// `DefId` refers to.
fn def_key(&self, def: DefId) -> hir_map::DefKey {
let cdata = self.get_crate_data(def.krate);
let path = decoder::def_path(&cdata, def.index);
let local_path = cdata.local_def_path();
local_path.into_iter().chain(path).collect()
decoder::def_key(&cdata, def.index)
}
fn relative_def_path(&self, def: DefId) -> hir_map::DefPath {
let cdata = self.get_crate_data(def.krate);
decoder::def_path(&cdata, def.index)
}
fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> {
@ -478,9 +492,13 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
{
loader::meta_section_name(target)
}
fn encode_type(&self, tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> Vec<u8>
fn encode_type(&self,
tcx: &TyCtxt<'tcx>,
ty: Ty<'tcx>,
def_id_to_string: fn(&TyCtxt<'tcx>, DefId) -> String)
-> Vec<u8>
{
encoder::encoded_ty(tcx, ty)
encoder::encoded_ty(tcx, ty, def_id_to_string)
}
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(ast::CrateNum, Option<PathBuf>)>

View File

@ -21,7 +21,7 @@ use index;
use loader;
use rustc::back::svh::Svh;
use rustc::front::map as ast_map;
use rustc::middle::cstore::{ExternCrate};
use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet};
use std::cell::{RefCell, Ref, Cell};
@ -31,9 +31,7 @@ use flate::Bytes;
use syntax::ast;
use syntax::attr;
use syntax::codemap;
use syntax::parse::token;
use syntax::parse::token::IdentInterner;
use syntax::util::small_vector::SmallVector;
pub use middle::cstore::{NativeLibraryKind, LinkagePreference};
pub use middle::cstore::{NativeStatic, NativeFramework, NativeUnknown};
@ -63,13 +61,16 @@ pub struct ImportedFileMap {
pub struct crate_metadata {
pub name: String,
pub local_path: RefCell<SmallVector<ast_map::PathElem>>,
pub local_def_path: RefCell<ast_map::DefPath>,
/// Information about the extern crate that caused this crate to
/// be loaded. If this is `None`, then the crate was injected
/// (e.g., by the allocator)
pub extern_crate: Cell<Option<ExternCrate>>,
pub data: MetadataBlob,
pub cnum_map: RefCell<cnum_map>,
pub cnum: ast::CrateNum,
pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
pub span: codemap::Span,
pub staged_api: bool,
pub index: index::Index,
@ -248,8 +249,11 @@ impl CStore {
impl crate_metadata {
pub fn data<'a>(&'a self) -> &'a [u8] { self.data.as_slice() }
pub fn name(&self) -> String { decoder::get_crate_name(self.data()) }
pub fn name(&self) -> &str { decoder::get_crate_name(self.data()) }
pub fn hash(&self) -> Svh { decoder::get_crate_hash(self.data()) }
pub fn disambiguator(&self) -> &str {
decoder::get_crate_disambiguator(self.data())
}
pub fn imported_filemaps<'a>(&'a self, codemap: &codemap::CodeMap)
-> Ref<'a, Vec<ImportedFileMap>> {
let filemaps = self.codemap_import_info.borrow();
@ -265,50 +269,6 @@ impl crate_metadata {
}
}
pub fn with_local_path<T, F>(&self, f: F) -> T
where F: Fn(&[ast_map::PathElem]) -> T
{
let cpath = self.local_path.borrow();
if cpath.is_empty() {
let name = ast_map::PathMod(token::intern(&self.name));
f(&[name])
} else {
f(cpath.as_slice())
}
}
pub fn update_local_path<'a, 'b>(&self, candidate: ast_map::PathElems<'a, 'b>) {
let mut cpath = self.local_path.borrow_mut();
let cap = cpath.len();
match cap {
0 => *cpath = candidate.collect(),
1 => (),
_ => {
let candidate: SmallVector<_> = candidate.collect();
if candidate.len() < cap {
*cpath = candidate;
}
},
}
}
pub fn local_def_path(&self) -> ast_map::DefPath {
let local_def_path = self.local_def_path.borrow();
if local_def_path.is_empty() {
let name = ast_map::DefPathData::DetachedCrate(token::intern(&self.name));
vec![ast_map::DisambiguatedDefPathData { data: name, disambiguator: 0 }]
} else {
local_def_path.clone()
}
}
pub fn update_local_def_path(&self, candidate: ast_map::DefPath) {
let mut local_def_path = self.local_def_path.borrow_mut();
if local_def_path.is_empty() || candidate.len() < local_def_path.len() {
*local_def_path = candidate;
}
}
pub fn is_allocator(&self) -> bool {
let attrs = decoder::get_crate_attributes(self.data());
attr::contains_name(&attrs, "allocator")

View File

@ -803,25 +803,43 @@ pub fn maybe_get_item_ast<'tcx>(cdata: Cmd, tcx: &TyCtxt<'tcx>, id: DefIndex)
debug!("Looking up item: {:?}", id);
let item_doc = cdata.lookup_item(id);
let item_did = item_def_id(item_doc, cdata);
let parent_def_id = DefId {
krate: cdata.cnum,
index: def_key(cdata, id).parent.unwrap()
};
let mut parent_path = item_path(item_doc);
parent_path.pop();
let mut parent_def_path = def_path(cdata, id);
parent_def_path.pop();
parent_def_path.data.pop();
if let Some(ast_doc) = reader::maybe_get_doc(item_doc, tag_ast as usize) {
let ii = decode_inlined_item(cdata, tcx, parent_path,
let ii = decode_inlined_item(cdata,
tcx,
parent_path,
parent_def_path,
ast_doc, item_did);
parent_def_id,
ast_doc,
item_did);
return FoundAst::Found(ii);
} else if let Some(parent_did) = item_parent_item(cdata, item_doc) {
// Remove the last element from the paths, since we are now
// trying to inline the parent.
parent_path.pop();
parent_def_path.pop();
let grandparent_def_id = DefId {
krate: cdata.cnum,
index: def_key(cdata, parent_def_id.index).parent.unwrap()
};
let mut grandparent_path = parent_path;
grandparent_path.pop();
let mut grandparent_def_path = parent_def_path;
grandparent_def_path.data.pop();
let parent_doc = cdata.lookup_item(parent_did.index);
if let Some(ast_doc) = reader::maybe_get_doc(parent_doc, tag_ast as usize) {
let ii = decode_inlined_item(cdata, tcx, parent_path,
parent_def_path,
ast_doc, parent_did);
let ii = decode_inlined_item(cdata,
tcx,
grandparent_path,
grandparent_def_path,
grandparent_def_id,
ast_doc,
parent_did);
if let &InlinedItem::Item(ref i) = ii {
return FoundAst::FoundParent(parent_did, i);
}
@ -1288,20 +1306,27 @@ pub fn get_crate_hash(data: &[u8]) -> Svh {
Svh::new(hashdoc.as_str_slice())
}
pub fn maybe_get_crate_name(data: &[u8]) -> Option<String> {
pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> {
let cratedoc = rbml::Doc::new(data);
reader::maybe_get_doc(cratedoc, tag_crate_crate_name).map(|doc| {
doc.as_str_slice().to_string()
doc.as_str_slice()
})
}
pub fn get_crate_disambiguator<'a>(data: &'a [u8]) -> &'a str {
let crate_doc = rbml::Doc::new(data);
let disambiguator_doc = reader::get_doc(crate_doc, tag_crate_disambiguator);
let slice: &'a str = disambiguator_doc.as_str_slice();
slice
}
pub fn get_crate_triple(data: &[u8]) -> Option<String> {
let cratedoc = rbml::Doc::new(data);
let triple_doc = reader::maybe_get_doc(cratedoc, tag_crate_triple);
triple_doc.map(|s| s.as_str().to_string())
}
pub fn get_crate_name(data: &[u8]) -> String {
pub fn get_crate_name(data: &[u8]) -> &str {
maybe_get_crate_name(data).expect("no crate name in crate")
}
@ -1738,7 +1763,9 @@ pub fn closure_ty<'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: &TyCtxt<'tcx>)
.parse_closure_ty()
}
fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey {
pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey {
debug!("def_key: id={:?}", id);
let item_doc = cdata.lookup_item(id);
match reader::maybe_get_doc(item_doc, tag_def_key) {
Some(def_key_doc) => {
let mut decoder = reader::Decoder::new(def_key_doc);
@ -1754,9 +1781,5 @@ fn def_key(item_doc: rbml::Doc) -> hir_map::DefKey {
pub fn def_path(cdata: Cmd, id: DefIndex) -> hir_map::DefPath {
debug!("def_path(id={:?})", id);
hir_map::definitions::make_def_path(id, |parent| {
debug!("def_path: parent={:?}", parent);
let parent_doc = cdata.lookup_item(parent);
def_key(parent_doc)
})
hir_map::DefPath::make(cdata.cnum, id, |parent| def_key(cdata, parent))
}

View File

@ -87,4 +87,6 @@ register_diagnostics! {
E0468, // an `extern crate` loading macros must be at the crate root
E0469, // imported macro not found
E0470, // reexported macro not found
E0519, // local crate and dependency have same (crate-name, disambiguator)
E0523, // two dependencies have same (crate-name, disambiguator) but different SVH
}

View File

@ -143,7 +143,7 @@ pub fn def_to_u64(did: DefId) -> u64 {
(did.krate as u64) << 32 | (did.index.as_usize() as u64)
}
pub fn def_to_string(did: DefId) -> String {
pub fn def_to_string(_tcx: &TyCtxt, did: DefId) -> String {
format!("{}:{}", did.krate, did.index.as_usize())
}
@ -1877,6 +1877,10 @@ fn encode_crate_name(rbml_w: &mut Encoder, crate_name: &str) {
rbml_w.wr_tagged_str(tag_crate_crate_name, crate_name);
}
fn encode_crate_disambiguator(rbml_w: &mut Encoder, crate_disambiguator: &str) {
rbml_w.wr_tagged_str(tag_crate_disambiguator, crate_disambiguator);
}
fn encode_crate_triple(rbml_w: &mut Encoder, triple: &str) {
rbml_w.wr_tagged_str(tag_crate_triple, triple);
}
@ -1987,6 +1991,7 @@ fn encode_metadata_inner(rbml_w: &mut Encoder,
encode_crate_name(rbml_w, &ecx.link_meta.crate_name);
encode_crate_triple(rbml_w, &ecx.tcx.sess.opts.target_triple);
encode_hash(rbml_w, &ecx.link_meta.crate_hash);
encode_crate_disambiguator(rbml_w, &ecx.tcx.sess.crate_disambiguator.get().as_str());
encode_dylib_dependency_formats(rbml_w, &ecx);
let mut i = rbml_w.writer.seek(SeekFrom::Current(0)).unwrap();
@ -2078,11 +2083,14 @@ fn encode_metadata_inner(rbml_w: &mut Encoder,
}
// Get the encoded string for a type
pub fn encoded_ty<'tcx>(tcx: &TyCtxt<'tcx>, t: Ty<'tcx>) -> Vec<u8> {
pub fn encoded_ty<'tcx>(tcx: &TyCtxt<'tcx>,
t: Ty<'tcx>,
def_id_to_string: fn(&TyCtxt<'tcx>, DefId) -> String)
-> Vec<u8> {
let mut wr = Cursor::new(Vec::new());
tyencode::enc_ty(&mut wr, &tyencode::ctxt {
diag: tcx.sess.diagnostic(),
ds: def_to_string,
ds: def_id_to_string,
tcx: tcx,
abbrevs: &RefCell::new(FnvHashMap())
}, t);

View File

@ -32,11 +32,11 @@ struct MacroLoader<'a> {
}
impl<'a> MacroLoader<'a> {
fn new(sess: &'a Session, cstore: &'a CStore) -> MacroLoader<'a> {
fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> MacroLoader<'a> {
MacroLoader {
sess: sess,
span_whitelist: HashSet::new(),
reader: CrateReader::new(sess, cstore),
reader: CrateReader::new(sess, cstore, crate_name),
macros: vec![],
}
}
@ -47,10 +47,13 @@ pub fn call_bad_macro_reexport(a: &Session, b: Span) {
}
/// Read exported macros.
pub fn read_macro_defs(sess: &Session, cstore: &CStore, krate: &ast::Crate)
pub fn read_macro_defs(sess: &Session,
cstore: &CStore,
krate: &ast::Crate,
crate_name: &str)
-> Vec<ast::MacroDef>
{
let mut loader = MacroLoader::new(sess, cstore);
let mut loader = MacroLoader::new(sess, cstore, crate_name);
// We need to error on `#[macro_use] extern crate` when it isn't at the
// crate root, because `$crate` won't work properly. Identify these by

View File

@ -37,7 +37,7 @@ use encoder;
pub struct ctxt<'a, 'tcx: 'a> {
pub diag: &'a Handler,
// Def -> str Callback:
pub ds: fn(DefId) -> String,
pub ds: fn(&TyCtxt<'tcx>, DefId) -> String,
// The type context.
pub tcx: &'a TyCtxt<'tcx>,
pub abbrevs: &'a abbrev_map<'tcx>
@ -99,7 +99,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
};
}
ty::TyEnum(def, substs) => {
write!(w, "t[{}|", (cx.ds)(def.did));
write!(w, "t[{}|", (cx.ds)(cx.tcx, def.did));
enc_substs(w, cx, substs);
write!(w, "]");
}
@ -137,7 +137,7 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
}
ty::TyFnDef(def_id, substs, f) => {
write!(w, "F");
write!(w, "{}|", (cx.ds)(def_id));
write!(w, "{}|", (cx.ds)(cx.tcx, def_id));
enc_substs(w, cx, substs);
enc_bare_fn_ty(w, cx, f);
}
@ -152,12 +152,12 @@ pub fn enc_ty<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>, t: Ty<'tcx
write!(w, "p[{}|{}|{}]", idx, space.to_uint(), name);
}
ty::TyStruct(def, substs) => {
write!(w, "a[{}|", (cx.ds)(def.did));
write!(w, "a[{}|", (cx.ds)(cx.tcx, def.did));
enc_substs(w, cx, substs);
write!(w, "]");
}
ty::TyClosure(def, ref substs) => {
write!(w, "k[{}|", (cx.ds)(def));
write!(w, "k[{}|", (cx.ds)(cx.tcx, def));
enc_substs(w, cx, &substs.func_substs);
for ty in &substs.upvar_tys {
enc_ty(w, cx, ty);
@ -310,7 +310,7 @@ fn enc_bound_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, br: ty::BoundRegion) {
}
ty::BrNamed(d, name) => {
write!(w, "[{}|{}]",
(cx.ds)(d),
(cx.ds)(cx.tcx, d),
name);
}
ty::BrFresh(id) => {
@ -324,7 +324,7 @@ fn enc_bound_region(w: &mut Cursor<Vec<u8>>, cx: &ctxt, br: ty::BoundRegion) {
pub fn enc_trait_ref<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
s: ty::TraitRef<'tcx>) {
write!(w, "{}|", (cx.ds)(s.def_id));
write!(w, "{}|", (cx.ds)(cx.tcx, s.def_id));
enc_substs(w, cx, s.substs);
}
@ -408,8 +408,8 @@ pub fn enc_existential_bounds<'a,'tcx>(w: &mut Cursor<Vec<u8>>,
pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>,
v: &ty::TypeParameterDef<'tcx>) {
write!(w, "{}:{}|{}|{}|{}|",
v.name, (cx.ds)(v.def_id),
v.space.to_uint(), v.index, (cx.ds)(v.default_def_id));
v.name, (cx.ds)(cx.tcx, v.def_id),
v.space.to_uint(), v.index, (cx.ds)(cx.tcx, v.default_def_id));
enc_opt(w, v.default, |w, t| enc_ty(w, cx, t));
enc_object_lifetime_default(w, cx, v.object_lifetime_default);
}
@ -417,7 +417,7 @@ pub fn enc_type_param_def<'a, 'tcx>(w: &mut Cursor<Vec<u8>>, cx: &ctxt<'a, 'tcx>
pub fn enc_region_param_def(w: &mut Cursor<Vec<u8>>, cx: &ctxt,
v: &ty::RegionParameterDef) {
write!(w, "{}:{}|{}|{}|",
v.name, (cx.ds)(v.def_id),
v.name, (cx.ds)(cx.tcx, v.def_id),
v.space.to_uint(), v.index);
for &r in &v.bounds {
write!(w, "R");
@ -477,7 +477,7 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor<Vec<u8>>,
enc_ty(w, cx, data);
}
ty::Predicate::ObjectSafe(trait_def_id) => {
write!(w, "O{}|", (cx.ds)(trait_def_id));
write!(w, "O{}|", (cx.ds)(cx.tcx, trait_def_id));
}
}
}

View File

@ -44,9 +44,12 @@ fn call_malformed_plugin_attribute(a: &Session, b: Span) {
}
/// Read plugin metadata and dynamically load registrar functions.
pub fn load_plugins(sess: &Session, cstore: &CStore, krate: &ast::Crate,
pub fn load_plugins(sess: &Session,
cstore: &CStore,
krate: &ast::Crate,
crate_name: &str,
addl_plugins: Option<Vec<String>>) -> Vec<PluginRegistrar> {
let mut loader = PluginLoader::new(sess, cstore);
let mut loader = PluginLoader::new(sess, cstore, crate_name);
for attr in &krate.attrs {
if !attr.check_name("plugin") {
@ -82,10 +85,10 @@ pub fn load_plugins(sess: &Session, cstore: &CStore, krate: &ast::Crate,
}
impl<'a> PluginLoader<'a> {
fn new(sess: &'a Session, cstore: &'a CStore) -> PluginLoader<'a> {
fn new(sess: &'a Session, cstore: &'a CStore, crate_name: &str) -> PluginLoader<'a> {
PluginLoader {
sess: sess,
reader: CrateReader::new(sess, cstore),
reader: CrateReader::new(sess, cstore, crate_name),
plugins: vec![],
}
}

View File

@ -23,11 +23,8 @@ use session::Session;
use middle::cstore::{self, CrateStore, LinkMeta};
use middle::cstore::{LinkagePreference, NativeLibraryKind};
use middle::dependency_format::Linkage;
use middle::ty::{Ty, TyCtxt};
use rustc::front::map::DefPath;
use trans::{CrateContext, CrateTranslation, gensym_name};
use trans::CrateTranslation;
use util::common::time;
use util::sha2::{Digest, Sha256};
use util::fs::fix_windows_verbatim_for_gcc;
use rustc_back::tempdir::TempDir;
@ -37,16 +34,13 @@ use std::env;
use std::ffi::OsString;
use std::fs;
use std::io::{self, Read, Write};
use std::iter::once;
use std::mem;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;
use flate;
use serialize::hex::ToHex;
use syntax::ast;
use syntax::codemap::Span;
use syntax::parse::token::{self, InternedString};
use syntax::attr::AttrMetaMethods;
use rustc_front::hir;
@ -81,58 +75,6 @@ pub const RLIB_BYTECODE_OBJECT_V1_DATA_OFFSET: usize =
RLIB_BYTECODE_OBJECT_V1_DATASIZE_OFFSET + 8;
/*
* Name mangling and its relationship to metadata. This is complex. Read
* carefully.
*
* The semantic model of Rust linkage is, broadly, that "there's no global
* namespace" between crates. Our aim is to preserve the illusion of this
* model despite the fact that it's not *quite* possible to implement on
* modern linkers. We initially didn't use system linkers at all, but have
* been convinced of their utility.
*
* There are a few issues to handle:
*
* - Linkers operate on a flat namespace, so we have to flatten names.
* We do this using the C++ namespace-mangling technique. Foo::bar
* symbols and such.
*
* - Symbols with the same name but different types need to get different
* linkage-names. We do this by hashing a string-encoding of the type into
* a fixed-size (currently 16-byte hex) cryptographic hash function (CHF:
* we use SHA256) to "prevent collisions". This is not airtight but 16 hex
* digits on uniform probability means you're going to need 2**32 same-name
* symbols in the same process before you're even hitting birthday-paradox
* collision probability.
*
* - Symbols in different crates but with same names "within" the crate need
* to get different linkage-names.
*
* - The hash shown in the filename needs to be predictable and stable for
* build tooling integration. It also needs to be using a hash function
* which is easy to use from Python, make, etc.
*
* So here is what we do:
*
* - Consider the package id; every crate has one (specified with crate_id
* attribute). If a package id isn't provided explicitly, we infer a
* versionless one from the output name. The version will end up being 0.0
* in this case. CNAME and CVERS are taken from this package id. For
* example, github.com/mozilla/CNAME#CVERS.
*
* - Define CMH as SHA256(crateid).
*
* - Define CMH8 as the first 8 characters of CMH.
*
* - Compile our crate to lib CNAME-CMH8-CVERS.so
*
* - Define STH(sym) as SHA256(CMH, type_str(sym))
*
* - Suffix a mangled sym with ::STH@CVERS, so that it is unique in the
* name, non-name metadata, and type sense, and versioned in the way
* system linkers understand.
*/
pub fn find_crate_name(sess: Option<&Session>,
attrs: &[ast::Attribute],
input: &Input) -> String {
@ -188,187 +130,12 @@ pub fn build_link_meta(sess: &Session,
-> LinkMeta {
let r = LinkMeta {
crate_name: name.to_owned(),
crate_hash: Svh::calculate(&sess.opts.cg.metadata, krate),
crate_hash: Svh::calculate(&sess.crate_disambiguator.get().as_str(), krate),
};
info!("{:?}", r);
return r;
}
fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String {
let output = symbol_hasher.result_bytes();
// 64 bits should be enough to avoid collisions.
output[.. 8].to_hex().to_string()
}
// This calculates STH for a symbol, as defined above
fn symbol_hash<'tcx>(tcx: &TyCtxt<'tcx>,
symbol_hasher: &mut Sha256,
t: Ty<'tcx>,
link_meta: &LinkMeta)
-> String {
// NB: do *not* use abbrevs here as we want the symbol names
// to be independent of one another in the crate.
symbol_hasher.reset();
symbol_hasher.input_str(&link_meta.crate_name);
symbol_hasher.input_str("-");
symbol_hasher.input_str(link_meta.crate_hash.as_str());
for meta in tcx.sess.crate_metadata.borrow().iter() {
symbol_hasher.input_str(&meta[..]);
}
symbol_hasher.input_str("-");
symbol_hasher.input(&tcx.sess.cstore.encode_type(tcx, t));
// Prefix with 'h' so that it never blends into adjacent digits
let mut hash = String::from("h");
hash.push_str(&truncated_hash_result(symbol_hasher));
hash
}
fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> String {
if let Some(h) = ccx.type_hashcodes().borrow().get(&t) {
return h.to_string()
}
let mut symbol_hasher = ccx.symbol_hasher().borrow_mut();
let hash = symbol_hash(ccx.tcx(), &mut *symbol_hasher, t, ccx.link_meta());
ccx.type_hashcodes().borrow_mut().insert(t, hash.clone());
hash
}
// Name sanitation. LLVM will happily accept identifiers with weird names, but
// gas doesn't!
// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
pub fn sanitize(s: &str) -> String {
let mut result = String::new();
for c in s.chars() {
match c {
// Escape these with $ sequences
'@' => result.push_str("$SP$"),
'*' => result.push_str("$BP$"),
'&' => result.push_str("$RF$"),
'<' => result.push_str("$LT$"),
'>' => result.push_str("$GT$"),
'(' => result.push_str("$LP$"),
')' => result.push_str("$RP$"),
',' => result.push_str("$C$"),
// '.' doesn't occur in types and functions, so reuse it
// for ':' and '-'
'-' | ':' => result.push('.'),
// These are legal symbols
'a' ... 'z'
| 'A' ... 'Z'
| '0' ... '9'
| '_' | '.' | '$' => result.push(c),
_ => {
result.push('$');
for c in c.escape_unicode().skip(1) {
match c {
'{' => {},
'}' => result.push('$'),
c => result.push(c),
}
}
}
}
}
// Underscore-qualify anything that didn't start as an ident.
if !result.is_empty() &&
result.as_bytes()[0] != '_' as u8 &&
! (result.as_bytes()[0] as char).is_xid_start() {
return format!("_{}", &result[..]);
}
return result;
}
pub fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: Option<&str>) -> String {
// Follow C++ namespace-mangling style, see
// http://en.wikipedia.org/wiki/Name_mangling for more info.
//
// It turns out that on OSX you can actually have arbitrary symbols in
// function names (at least when given to LLVM), but this is not possible
// when using unix's linker. Perhaps one day when we just use a linker from LLVM
// we won't need to do this name mangling. The problem with name mangling is
// that it seriously limits the available characters. For example we can't
// have things like &T in symbol names when one would theoretically
// want them for things like impls of traits on that type.
//
// To be able to work on all platforms and get *some* reasonable output, we
// use C++ name-mangling.
let mut n = String::from("_ZN"); // _Z == Begin name-sequence, N == nested
fn push(n: &mut String, s: &str) {
let sani = sanitize(s);
n.push_str(&format!("{}{}", sani.len(), sani));
}
// First, connect each component with <len, name> pairs.
for data in path {
push(&mut n, &data);
}
if let Some(s) = hash {
push(&mut n, s)
}
n.push('E'); // End name-sequence.
n
}
pub fn exported_name(path: DefPath, hash: &str) -> String {
let path = path.into_iter()
.map(|e| e.data.as_interned_str());
mangle(path, Some(hash))
}
pub fn mangle_exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, path: DefPath,
t: Ty<'tcx>, id: ast::NodeId) -> String {
let mut hash = get_symbol_hash(ccx, t);
// Paths can be completely identical for different nodes,
// e.g. `fn foo() { { fn a() {} } { fn a() {} } }`, so we
// generate unique characters from the node id. For now
// hopefully 3 characters is enough to avoid collisions.
const EXTRA_CHARS: &'static str =
"abcdefghijklmnopqrstuvwxyz\
ABCDEFGHIJKLMNOPQRSTUVWXYZ\
0123456789";
let id = id as usize;
let extra1 = id % EXTRA_CHARS.len();
let id = id / EXTRA_CHARS.len();
let extra2 = id % EXTRA_CHARS.len();
let id = id / EXTRA_CHARS.len();
let extra3 = id % EXTRA_CHARS.len();
hash.push(EXTRA_CHARS.as_bytes()[extra1] as char);
hash.push(EXTRA_CHARS.as_bytes()[extra2] as char);
hash.push(EXTRA_CHARS.as_bytes()[extra3] as char);
exported_name(path, &hash[..])
}
pub fn mangle_internal_name_by_type_and_seq<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
t: Ty<'tcx>,
name: &str) -> String {
let path = [token::intern(&t.to_string()).as_str(), gensym_name(name).as_str()];
let hash = get_symbol_hash(ccx, t);
mangle(path.iter().cloned(), Some(&hash[..]))
}
pub fn mangle_internal_name_by_path_and_seq(path: DefPath, flav: &str) -> String {
let names =
path.into_iter()
.map(|e| e.data.as_interned_str())
.chain(once(gensym_name(flav).as_str())); // append unique version of "flav"
mangle(names, None)
}
pub fn get_linker(sess: &Session) -> (String, Command) {
if let Some(ref linker) = sess.opts.cg.linker {
(linker.clone(), Command::new(linker))

View File

@ -359,6 +359,7 @@ impl<'a> Linker for MsvcLinker<'a> {
for symbol in symbols {
writeln!(f, " {}", symbol)?;
}
Ok(())
})();
if let Err(e) = res {

View File

@ -0,0 +1,378 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! The Rust Linkage Model and Symbol Names
//! =======================================
//!
//! The semantic model of Rust linkage is, broadly, that "there's no global
//! namespace" between crates. Our aim is to preserve the illusion of this
//! model despite the fact that it's not *quite* possible to implement on
//! modern linkers. We initially didn't use system linkers at all, but have
//! been convinced of their utility.
//!
//! There are a few issues to handle:
//!
//! - Linkers operate on a flat namespace, so we have to flatten names.
//! We do this using the C++ namespace-mangling technique. Foo::bar
//! symbols and such.
//!
//! - Symbols for distinct items with the same *name* need to get different
//! linkage-names. Examples of this are monomorphizations of functions or
//! items within anonymous scopes that end up having the same path.
//!
//! - Symbols in different crates but with same names "within" the crate need
//! to get different linkage-names.
//!
//! - Symbol names should be deterministic: Two consecutive runs of the
//! compiler over the same code base should produce the same symbol names for
//! the same items.
//!
//! - Symbol names should not depend on any global properties of the code base,
//! so that small modifications to the code base do not result in all symbols
//! changing. In previous versions of the compiler, symbol names incorporated
//! the SVH (Stable Version Hash) of the crate. This scheme turned out to be
//! infeasible when used in conjunction with incremental compilation because
//! small code changes would invalidate all symbols generated previously.
//!
//! - Even symbols from different versions of the same crate should be able to
//! live next to each other without conflict.
//!
//! In order to fulfill the above requirements the following scheme is used by
//! the compiler:
//!
//! The main tool for avoiding naming conflicts is the incorporation of a 64-bit
//! hash value into every exported symbol name. Anything that makes a difference
//! to the symbol being named, but does not show up in the regular path needs to
//! be fed into this hash:
//!
//! - Different monomorphizations of the same item have the same path but differ
//! in their concrete type parameters, so these parameters are part of the
//! data being digested for the symbol hash.
//!
//! - Rust allows items to be defined in anonymous scopes, such as in
//! `fn foo() { { fn bar() {} } { fn bar() {} } }`. Both `bar` functions have
//! the path `foo::bar`, since the anonymous scopes do not contribute to the
//! path of an item. The compiler already handles this case via so-called
//! disambiguating `DefPaths` which use indices to distinguish items with the
//! same name. The DefPaths of the functions above are thus `foo[0]::bar[0]`
//! and `foo[0]::bar[1]`. In order to incorporate this disambiguation
//! information into the symbol name too, these indices are fed into the
//! symbol hash, so that the above two symbols would end up with different
//! hash values.
//!
//! The two measures described above suffice to avoid intra-crate conflicts. In
//! order to also avoid inter-crate conflicts two more measures are taken:
//!
//! - The name of the crate containing the symbol is prepended to the symbol
//! name, i.e. symbols are "crate qualified". For example, a function `foo` in
//! module `bar` in crate `baz` would get a symbol name like
//! `baz::bar::foo::{hash}` instead of just `bar::foo::{hash}`. This avoids
//! simple conflicts between functions from different crates.
//!
//! - In order to be able to also use symbols from two versions of the same
//! crate (which naturally also have the same name), a stronger measure is
//! required: The compiler accepts an arbitrary "disambiguator" value via the
//! `-C metadata` commandline argument. This disambiguator is then fed into
//! the symbol hash of every exported item. Consequently, the symbols in two
//! identical crates but with different disambiguators are not in conflict
//! with each other. This facility is mainly intended to be used by build
//! tools like Cargo.
//!
//! A note on symbol name stability
//! -------------------------------
//! Previous versions of the compiler resorted to feeding NodeIds into the
//! symbol hash in order to disambiguate between items with the same path. The
//! current version of the name generation algorithm takes great care not to do
//! that, since NodeIds are notoriously unstable: A small change to the
//! code base will offset all NodeIds after the change and thus, much as using
//! the SVH in the hash, invalidate an unbounded number of symbol names. This
//! makes re-using previously compiled code for incremental compilation
//! virtually impossible. Thus, symbol hash generation exclusively relies on
//! DefPaths which are much more robust in the face of changes to the code base.
use trans::{CrateContext, Instance, gensym_name};
use util::sha2::{Digest, Sha256};
use rustc::middle::cstore;
use rustc::middle::def_id::DefId;
use rustc::middle::ty::{self, TypeFoldable};
use rustc::middle::ty::item_path::{ItemPathBuffer, RootMode};
use rustc::front::map::definitions::{DefPath, DefPathData};
use std::fmt::Write;
use syntax::parse::token::{self, InternedString};
use serialize::hex::ToHex;
pub fn def_id_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_id: DefId) -> String {
let def_path = tcx.def_path(def_id);
def_path_to_string(tcx, &def_path)
}
pub fn def_path_to_string<'tcx>(tcx: &ty::TyCtxt<'tcx>, def_path: &DefPath) -> String {
let mut s = String::with_capacity(def_path.data.len() * 16);
s.push_str(&tcx.crate_name(def_path.krate));
s.push_str("/");
s.push_str(&tcx.crate_disambiguator(def_path.krate));
for component in &def_path.data {
write!(s,
"::{}[{}]",
component.data.as_interned_str(),
component.disambiguator)
.unwrap();
}
s
}
fn get_symbol_hash<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// path to the item this name is for
def_path: &DefPath,
// type of the item, without any generic
// parameters substituted; this is
// included in the hash as a kind of
// safeguard.
item_type: ty::Ty<'tcx>,
// values for generic type parameters,
// if any.
parameters: &[ty::Ty<'tcx>])
-> String {
debug!("get_symbol_hash(def_path={:?}, parameters={:?})",
def_path, parameters);
let tcx = ccx.tcx();
let mut hash_state = ccx.symbol_hasher().borrow_mut();
hash_state.reset();
// the main symbol name is not necessarily unique; hash in the
// compiler's internal def-path, guaranteeing each symbol has a
// truly unique path
hash_state.input_str(&def_path_to_string(tcx, def_path));
// Include the main item-type. Note that, in this case, the
// assertions about `needs_subst` may not hold, but this item-type
// ought to be the same for every reference anyway.
assert!(!item_type.has_erasable_regions());
let encoded_item_type = tcx.sess.cstore.encode_type(tcx, item_type, def_id_to_string);
hash_state.input(&encoded_item_type[..]);
// also include any type parameters (for generic items)
for t in parameters {
assert!(!t.has_erasable_regions());
assert!(!t.needs_subst());
let encoded_type = tcx.sess.cstore.encode_type(tcx, t, def_id_to_string);
hash_state.input(&encoded_type[..]);
}
return format!("h{}", truncated_hash_result(&mut *hash_state));
fn truncated_hash_result(symbol_hasher: &mut Sha256) -> String {
let output = symbol_hasher.result_bytes();
// 64 bits should be enough to avoid collisions.
output[.. 8].to_hex()
}
}
fn exported_name_with_opt_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
instance: &Instance<'tcx>,
suffix: Option<&str>)
-> String {
let &Instance { def: mut def_id, ref substs } = instance;
debug!("exported_name_with_opt_suffix(def_id={:?}, substs={:?}, suffix={:?})",
def_id, substs, suffix);
if let Some(node_id) = ccx.tcx().map.as_local_node_id(def_id) {
if let Some(&src_def_id) = ccx.external_srcs().borrow().get(&node_id) {
def_id = src_def_id;
}
}
let def_path = ccx.tcx().def_path(def_id);
assert_eq!(def_path.krate, def_id.krate);
// We want to compute the "type" of this item. Unfortunately, some
// kinds of items (e.g., closures) don't have an entry in the
// item-type array. So walk back up the find the closest parent
// that DOES have an entry.
let mut ty_def_id = def_id;
let instance_ty;
loop {
let key = ccx.tcx().def_key(ty_def_id);
match key.disambiguated_data.data {
DefPathData::TypeNs(_) |
DefPathData::ValueNs(_) => {
instance_ty = ccx.tcx().lookup_item_type(ty_def_id);
break;
}
_ => {
// if we're making a symbol for something, there ought
// to be a value or type-def or something in there
// *somewhere*
ty_def_id.index = key.parent.unwrap_or_else(|| {
panic!("finding type for {:?}, encountered def-id {:?} with no \
parent", def_id, ty_def_id);
});
}
}
}
// Erase regions because they may not be deterministic when hashed
// and should not matter anyhow.
let instance_ty = ccx.tcx().erase_regions(&instance_ty.ty);
let hash = get_symbol_hash(ccx, &def_path, instance_ty, substs.types.as_slice());
let mut buffer = SymbolPathBuffer {
names: Vec::with_capacity(def_path.data.len())
};
ccx.tcx().push_item_path(&mut buffer, def_id);
if let Some(suffix) = suffix {
buffer.push(suffix);
}
mangle(buffer.names.into_iter(), Some(&hash[..]))
}
struct SymbolPathBuffer {
names: Vec<InternedString>,
}
impl ItemPathBuffer for SymbolPathBuffer {
fn root_mode(&self) -> &RootMode {
const ABSOLUTE: &'static RootMode = &RootMode::Absolute;
ABSOLUTE
}
fn push(&mut self, text: &str) {
self.names.push(token::intern(text).as_str());
}
}
pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
instance: &Instance<'tcx>)
-> String {
exported_name_with_opt_suffix(ccx, instance, None)
}
pub fn exported_name_with_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
instance: &Instance<'tcx>,
suffix: &str)
-> String {
exported_name_with_opt_suffix(ccx, instance, Some(suffix))
}
/// Only symbols that are invisible outside their compilation unit should use a
/// name generated by this function.
pub fn internal_name_from_type_and_suffix<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
t: ty::Ty<'tcx>,
suffix: &str)
-> String {
let path = [token::intern(&t.to_string()).as_str(),
gensym_name(suffix).as_str()];
let def_path = DefPath {
data: vec![],
krate: cstore::LOCAL_CRATE,
};
let hash = get_symbol_hash(ccx, &def_path, t, &[]);
mangle(path.iter().cloned(), Some(&hash[..]))
}
// Name sanitation. LLVM will happily accept identifiers with weird names, but
// gas doesn't!
// gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
pub fn sanitize(s: &str) -> String {
let mut result = String::new();
for c in s.chars() {
match c {
// Escape these with $ sequences
'@' => result.push_str("$SP$"),
'*' => result.push_str("$BP$"),
'&' => result.push_str("$RF$"),
'<' => result.push_str("$LT$"),
'>' => result.push_str("$GT$"),
'(' => result.push_str("$LP$"),
')' => result.push_str("$RP$"),
',' => result.push_str("$C$"),
// '.' doesn't occur in types and functions, so reuse it
// for ':' and '-'
'-' | ':' => result.push('.'),
// These are legal symbols
'a' ... 'z'
| 'A' ... 'Z'
| '0' ... '9'
| '_' | '.' | '$' => result.push(c),
_ => {
result.push('$');
for c in c.escape_unicode().skip(1) {
match c {
'{' => {},
'}' => result.push('$'),
c => result.push(c),
}
}
}
}
}
// Underscore-qualify anything that didn't start as an ident.
if !result.is_empty() &&
result.as_bytes()[0] != '_' as u8 &&
! (result.as_bytes()[0] as char).is_xid_start() {
return format!("_{}", &result[..]);
}
return result;
}
pub fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: Option<&str>) -> String {
// Follow C++ namespace-mangling style, see
// http://en.wikipedia.org/wiki/Name_mangling for more info.
//
// It turns out that on OSX you can actually have arbitrary symbols in
// function names (at least when given to LLVM), but this is not possible
// when using unix's linker. Perhaps one day when we just use a linker from LLVM
// we won't need to do this name mangling. The problem with name mangling is
// that it seriously limits the available characters. For example we can't
// have things like &T in symbol names when one would theoretically
// want them for things like impls of traits on that type.
//
// To be able to work on all platforms and get *some* reasonable output, we
// use C++ name-mangling.
let mut n = String::from("_ZN"); // _Z == Begin name-sequence, N == nested
fn push(n: &mut String, s: &str) {
let sani = sanitize(s);
n.push_str(&format!("{}{}", sani.len(), sani));
}
// First, connect each component with <len, name> pairs.
for data in path {
push(&mut n, &data);
}
if let Some(s) = hash {
push(&mut n, s)
}
n.push('E'); // End name-sequence.
n
}

View File

@ -69,6 +69,7 @@ pub mod back {
pub mod linker;
pub mod link;
pub mod lto;
pub mod symbol_names;
pub mod write;
pub mod msvc;
}

View File

@ -90,7 +90,7 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
for n in self.tcx.sess.cstore.crates() {
result.push(CrateData {
name: self.tcx.sess.cstore.crate_name(n),
name: (&self.tcx.sess.cstore.crate_name(n)[..]).to_owned(),
number: n,
});
}

View File

@ -7,6 +7,7 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Translate the completed AST to the LLVM IR.
//!
//! Some functions here, such as trans_block and trans_expr, return a value --
@ -29,8 +30,7 @@ pub use self::ValueOrigin::*;
use super::CrateTranslation;
use super::ModuleTranslation;
use back::link::mangle_exported_name;
use back::link;
use back::{link, symbol_names};
use lint;
use llvm::{BasicBlockRef, Linkage, ValueRef, Vector, get_param};
use llvm;
@ -84,6 +84,7 @@ use trans::machine::{llalign_of_min, llsize_of, llsize_of_real};
use trans::meth;
use trans::mir;
use trans::monomorphize::{self, Instance};
use trans::symbol_names_test;
use trans::tvec;
use trans::type_::Type;
use trans::type_of;
@ -2421,10 +2422,11 @@ pub fn create_entry_wrapper(ccx: &CrateContext, sp: Span, main_llfn: ValueRef) {
}
pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
id: ast::NodeId,
ty: Ty<'tcx>,
instance: Instance<'tcx>,
attrs: &[ast::Attribute])
-> String {
let id = ccx.tcx().map.as_local_node_id(instance.def).unwrap();
match ccx.external_srcs().borrow().get(&id) {
Some(&did) => {
let sym = ccx.sess().cstore.item_symbol(did);
@ -2438,16 +2440,16 @@ pub fn exported_name<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
// Use provided name
Some(name) => name.to_string(),
_ => {
let path = ccx.tcx().map.def_path_from_id(id);
if attr::contains_name(attrs, "no_mangle") {
// Don't mangle
path.last().unwrap().data.to_string()
let path = ccx.tcx().map.def_path_from_id(id);
path.data.last().unwrap().data.to_string()
} else {
match weak_lang_items::link_name(attrs) {
Some(name) => name.to_string(),
None => {
// Usual name mangling
mangle_exported_name(ccx, path, ty, id)
symbol_names::exported_name(ccx, &instance)
}
}
}
@ -2755,6 +2757,8 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>,
}
collector::print_collection_results(&ccx);
symbol_names_test::report_symbol_names(&ccx);
}
for ccx in shared_ccx.iter() {

View File

@ -18,7 +18,7 @@ pub use self::CalleeData::*;
pub use self::CallArgs::*;
use arena::TypedArena;
use back::link;
use back::symbol_names;
use llvm::{self, ValueRef, get_params};
use middle::cstore::LOCAL_CRATE;
use middle::def_id::DefId;
@ -378,8 +378,10 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
//
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, bare_fn_ty,
"fn_pointer_shim");
let function_name =
symbol_names::internal_name_from_type_and_suffix(ccx,
bare_fn_ty,
"fn_pointer_shim");
let llfn = declare::define_internal_fn(ccx, &function_name, tuple_fn_ty);
//
@ -513,7 +515,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
Some(hir_map::NodeImplItem(&hir::ImplItem {
ref attrs, id, span, node: hir::ImplItemKind::Method(..), ..
})) => {
let sym = exported_name(ccx, id, ty, attrs);
let sym = exported_name(ccx, instance, attrs);
if declare::get_defined_value(ccx, &sym).is_some() {
ccx.sess().span_fatal(span,

View File

@ -9,7 +9,7 @@
// except according to those terms.
use arena::TypedArena;
use back::link::{self, mangle_internal_name_by_path_and_seq};
use back::symbol_names;
use llvm::{ValueRef, get_param, get_params};
use middle::def_id::DefId;
use middle::infer;
@ -152,8 +152,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
return llfn;
}
let path = tcx.def_path(closure_id);
let symbol = mangle_internal_name_by_path_and_seq(path, "closure");
let symbol = symbol_names::exported_name(ccx, &instance);
// Compute the rust-call form of the closure call method.
let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any);
@ -383,7 +382,8 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
});
// Create the by-value helper.
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim");
let function_name =
symbol_names::internal_name_from_type_and_suffix(ccx, llonce_fn_ty, "once_shim");
let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
let (block_arena, fcx): (TypedArena<_>, FunctionContext);

View File

@ -1261,28 +1261,20 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
fn push_item_name(ccx: &CrateContext,
def_id: DefId,
output: &mut String) {
if def_id.is_local() {
let node_id = ccx.tcx().map.as_local_node_id(def_id).unwrap();
let inlined_from = ccx.external_srcs()
.borrow()
.get(&node_id)
.map(|def_id| *def_id);
let def_path = ccx.tcx().def_path(def_id);
if let Some(extern_def_id) = inlined_from {
push_item_name(ccx, extern_def_id, output);
return;
}
// some_crate::
output.push_str(&ccx.tcx().crate_name(def_path.krate));
output.push_str("::");
output.push_str(&ccx.link_meta().crate_name);
output.push_str("::");
}
for part in ccx.tcx().def_path(def_id) {
// foo::bar::ItemName::
for part in ccx.tcx().def_path(def_id).data {
output.push_str(&format!("{}[{}]::",
part.data.as_interned_str(),
part.disambiguator));
}
// remove final "::"
output.pop();
output.pop();
}

View File

@ -1032,7 +1032,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId)
// we need to get the symbol from metadata instead of
// using the current crate's name/version
// information in the hash of the symbol
let sym = exported_name(ccx, id, ty, attrs);
let sym = exported_name(ccx, instance, attrs);
debug!("making {}", sym);
// Create the global before evaluating the initializer;

View File

@ -25,7 +25,8 @@ use trans::debuginfo;
use trans::declare;
use trans::glue::DropGlueKind;
use trans::mir::CachedMir;
use trans::monomorphize::Instance;
use trans::Instance;
use trans::collector::{TransItem, TransItemState};
use trans::type_::{Type, TypeNames};
use middle::subst::{Substs, VecPerParamSpace};

View File

@ -90,10 +90,7 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(ccx: &CrateContext)
pub fn needs_gdb_debug_scripts_section(ccx: &CrateContext) -> bool {
let omit_gdb_pretty_printer_section =
attr::contains_name(&ccx.tcx()
.map
.krate()
.attrs,
attr::contains_name(&ccx.tcx().map.krate_attrs(),
"omit_gdb_pretty_printer_section");
!omit_gdb_pretty_printer_section &&

View File

@ -14,7 +14,7 @@
use std;
use back::link;
use back::symbol_names;
use llvm;
use llvm::{ValueRef, get_param};
use middle::lang_items::ExchangeFreeFnLangItem;
@ -259,7 +259,12 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
return llfn;
};
let fn_nm = link::mangle_internal_name_by_type_and_seq(ccx, t, "drop");
let suffix = match g {
DropGlueKind::Ty(_) => "drop",
DropGlueKind::TyContents(_) => "drop_contents",
};
let fn_nm = symbol_names::internal_name_from_type_and_suffix(ccx, t, suffix);
assert!(declare::get_defined_value(ccx, &fn_nm).is_none());
let llfn = declare::declare_cfn(ccx, &fn_nm, llfnty);
ccx.available_drop_glues().borrow_mut().insert(g, fn_nm);

View File

@ -97,6 +97,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option<DefId> {
for (ast_v, ty_v) in ast_vs.iter().zip(ty_vs.iter()) {
if ty_v.did == fn_id { my_id = ast_v.node.data.id(); }
ccx.external().borrow_mut().insert(ty_v.did, Some(ast_v.node.data.id()));
ccx.external_srcs().borrow_mut().insert(ast_v.node.data.id(), ty_v.did);
}
}
hir::ItemStruct(ref struct_def, _) => {
@ -105,6 +106,7 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option<DefId> {
non-tuple struct")
} else {
ccx.external().borrow_mut().insert(fn_id, Some(struct_def.id()));
ccx.external_srcs().borrow_mut().insert(struct_def.id(), fn_id);
my_id = struct_def.id();
}
}

View File

@ -11,7 +11,7 @@
use std::rc::Rc;
use arena::TypedArena;
use back::link;
use back::symbol_names;
use llvm::{ValueRef, get_params};
use middle::def_id::DefId;
use middle::infer;
@ -89,7 +89,8 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
let sig = infer::normalize_associated_type(tcx, &sig);
let fn_ty = FnType::new(ccx, method_ty.fn_abi(), &sig, &[]);
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, method_ty, "object_shim");
let function_name =
symbol_names::internal_name_from_type_and_suffix(ccx, method_ty, "object_shim");
let llfn = declare::define_internal_fn(ccx, &function_name, method_ty);
let empty_substs = tcx.mk_substs(Substs::empty());

View File

@ -15,6 +15,7 @@ pub use self::base::trans_crate;
pub use self::context::CrateContext;
pub use self::common::gensym_name;
pub use self::disr::Disr;
pub use self::monomorphize::Instance;
#[macro_use]
mod macros;
@ -58,6 +59,7 @@ mod meth;
mod mir;
mod monomorphize;
mod collector;
mod symbol_names_test;
mod tvec;
mod type_;
mod type_of;

View File

@ -8,13 +8,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use back::link::exported_name;
use back::symbol_names;
use llvm::ValueRef;
use llvm;
use middle::def_id::DefId;
use middle::infer::normalize_associated_type;
use middle::subst;
use middle::subst::{Subst, Substs};
use middle::ty::{self, Ty, TyCtxt};
use middle::ty::fold::{TypeFolder, TypeFoldable};
use trans::attributes;
use trans::base::{push_ctxt};
@ -22,7 +23,6 @@ use trans::base::trans_fn;
use trans::base;
use trans::common::*;
use trans::declare;
use middle::ty::{self, Ty, TyCtxt};
use trans::Disr;
use rustc::front::map as hir_map;
use rustc::util::ppaux;
@ -33,7 +33,6 @@ use syntax::attr;
use syntax::errors;
use std::fmt;
use std::hash::{Hasher, Hash, SipHasher};
pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_id: DefId,
@ -90,22 +89,13 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
monomorphizing.insert(fn_id, depth + 1);
}
let hash;
let s = {
let mut state = SipHasher::new();
instance.hash(&mut state);
mono_ty.hash(&mut state);
let symbol = symbol_names::exported_name(ccx, &instance);
hash = format!("h{}", state.finish());
let path = ccx.tcx().map.def_path(fn_id);
exported_name(path, &hash[..])
};
debug!("monomorphize_fn mangled to {}", s);
assert!(declare::get_defined_value(ccx, &s).is_none());
debug!("monomorphize_fn mangled to {}", symbol);
assert!(declare::get_defined_value(ccx, &symbol).is_none());
// FIXME(nagisa): perhaps needs a more fine grained selection?
let lldecl = declare::define_internal_fn(ccx, &s, mono_ty);
let lldecl = declare::define_internal_fn(ccx, &symbol, mono_ty);
// FIXME(eddyb) Doubt all extern fn should allow unwinding.
attributes::unwind(lldecl, true);
@ -137,9 +127,10 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
base::update_linkage(ccx, lldecl, None, base::OriginalTranslation);
attributes::from_fn_attrs(ccx, attrs, lldecl);
let is_first = !ccx.available_monomorphizations().borrow().contains(&s);
let is_first = !ccx.available_monomorphizations().borrow()
.contains(&symbol);
if is_first {
ccx.available_monomorphizations().borrow_mut().insert(s.clone());
ccx.available_monomorphizations().borrow_mut().insert(symbol.clone());
}
let trans_everywhere = attr::requests_inline(attrs);

View File

@ -0,0 +1,86 @@
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Walks the crate looking for items/impl-items/trait-items that have
//! either a `rustc_symbol_name` or `rustc_item_path` attribute and
//! generates an error giving, respectively, the symbol name or
//! item-path. This is used for unit testing the code that generates
//! paths etc in all kinds of annoying scenarios.
use back::symbol_names;
use rustc::middle::ty::TyCtxt;
use rustc_front::hir;
use rustc_front::intravisit::{self, Visitor};
use syntax::ast;
use syntax::attr::AttrMetaMethods;
use trans::common::CrateContext;
use trans::monomorphize::Instance;
const SYMBOL_NAME: &'static str = "rustc_symbol_name";
const ITEM_PATH: &'static str = "rustc_item_path";
pub fn report_symbol_names(ccx: &CrateContext) {
// if the `rustc_attrs` feature is not enabled, then the
// attributes we are interested in cannot be present anyway, so
// skip the walk.
let tcx = ccx.tcx();
if !tcx.sess.features.borrow().rustc_attrs {
return;
}
let _ignore = tcx.dep_graph.in_ignore();
let mut visitor = SymbolNamesTest { ccx: ccx, tcx: tcx };
tcx.map.krate().visit_all_items(&mut visitor);
}
struct SymbolNamesTest<'a, 'tcx:'a> {
ccx: &'a CrateContext<'a, 'tcx>,
tcx: &'a TyCtxt<'tcx>,
}
impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> {
fn process_attrs(&mut self,
node_id: ast::NodeId) {
let def_id = self.tcx.map.local_def_id(node_id);
for attr in self.tcx.get_attrs(def_id).iter() {
if attr.check_name(SYMBOL_NAME) {
// for now, can only use on monomorphic names
let instance = Instance::mono(self.tcx, def_id);
let name = symbol_names::exported_name(self.ccx, &instance);
self.tcx.sess.span_err(attr.span, &format!("symbol-name({})", name));
} else if attr.check_name(ITEM_PATH) {
let path = self.tcx.item_path_str(def_id);
self.tcx.sess.span_err(attr.span, &format!("item-path({})", path));
}
// (*) The formatting of `tag({})` is chosen so that tests can elect
// to test the entirety of the string, if they choose, or else just
// some subset.
}
}
}
impl<'a, 'tcx> Visitor<'tcx> for SymbolNamesTest<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
self.process_attrs(item.id);
intravisit::walk_item(self, item);
}
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
self.process_attrs(ti.id);
intravisit::walk_trait_item(self, ti)
}
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
self.process_attrs(ii.id);
intravisit::walk_impl_item(self, ii)
}
}

View File

@ -241,7 +241,7 @@ impl Clean<ExternalCrate> for CrateNum {
}
});
ExternalCrate {
name: cx.sess().cstore.crate_name(self.0),
name: (&cx.sess().cstore.crate_name(self.0)[..]).to_owned(),
attrs: cx.sess().cstore.crate_attrs(self.0).clean(cx),
primitives: primitives,
}

View File

@ -349,6 +349,10 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeGat
"the `#[rustc_if_this_changed]` attribute \
is just used for rustc unit tests \
and will never be stable")),
("rustc_symbol_name", Whitelisted, Gated("rustc_attrs",
"internal rustc attributes will never be stable")),
("rustc_item_path", Whitelisted, Gated("rustc_attrs",
"internal rustc attributes will never be stable")),
("rustc_move_fragments", Normal, Gated("rustc_attrs",
"the `#[rustc_move_fragments]` attribute \
is just used for rustc unit tests \
@ -579,6 +583,7 @@ pub struct Features {
pub const_indexing: bool,
pub static_recursion: bool,
pub default_type_parameter_fallback: bool,
pub rustc_attrs: bool,
pub type_macros: bool,
pub cfg_target_feature: bool,
pub cfg_target_vendor: bool,
@ -614,6 +619,7 @@ impl Features {
const_indexing: false,
static_recursion: false,
default_type_parameter_fallback: false,
rustc_attrs: false,
type_macros: false,
cfg_target_feature: false,
cfg_target_vendor: false,
@ -1225,6 +1231,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &Handler,
const_indexing: cx.has_feature("const_indexing"),
static_recursion: cx.has_feature("static_recursion"),
default_type_parameter_fallback: cx.has_feature("default_type_parameter_fallback"),
rustc_attrs: cx.has_feature("rustc_attrs"),
type_macros: cx.has_feature("type_macros"),
cfg_target_feature: cx.has_feature("cfg_target_feature"),
cfg_target_vendor: cx.has_feature("cfg_target_vendor"),

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub trait Foo {
fn bar(&self);
fn foo(&mut self) {}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub trait Foo {
#[doc(hidden)]
fn foo(&self) {}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
#![doc(html_root_url = "http://example.com/")]
/// dox

View File

@ -8,6 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
#![doc(html_root_url = "http://example.com")]

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
use std::ops::Deref;
pub struct Foo;

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub trait Trait {
type Output;
}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub trait Deref {
type Target: ?Sized;

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub trait Foo {
type Bar;
fn foo(&self) {}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub struct Foo;
impl Foo {

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub mod foo {
pub trait Foo {}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
#![feature(const_fn)]
pub const fn foo() {}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: -Cmetadata=aux
pub struct Foo;
#[doc(hidden)]

View File

@ -19,12 +19,12 @@ extern crate cgu_extern_closures;
//~ TRANS_ITEM fn cross_crate_closures::main[0]
fn main() {
//~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn[0]
//~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn[0]::{{closure}}[0]
//~ TRANS_ITEM fn cgu_extern_closures::inlined_fn[0]
//~ TRANS_ITEM fn cgu_extern_closures::inlined_fn[0]::{{closure}}[0]
let _ = cgu_extern_closures::inlined_fn(1, 2);
//~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn_generic[0]<i32>
//~ TRANS_ITEM fn cgu_extern_closures[0]::inlined_fn_generic[0]::{{closure}}[0]<i32>
//~ TRANS_ITEM fn cgu_extern_closures::inlined_fn_generic[0]<i32>
//~ TRANS_ITEM fn cgu_extern_closures::inlined_fn_generic[0]::{{closure}}[0]<i32>
let _ = cgu_extern_closures::inlined_fn_generic(3, 4, 5i32);
// Nothing should be generated for this call, we just link to the instance instance

View File

@ -19,12 +19,12 @@ extern crate cgu_generic_function;
//~ TRANS_ITEM fn cross_crate_generic_functions::main[0]
fn main()
{
//~ TRANS_ITEM fn cgu_generic_function[0]::bar[0]<u32>
//~ TRANS_ITEM fn cgu_generic_function[0]::foo[0]<u32>
//~ TRANS_ITEM fn cgu_generic_function::bar[0]<u32>
//~ TRANS_ITEM fn cgu_generic_function::foo[0]<u32>
let _ = cgu_generic_function::foo(1u32);
//~ TRANS_ITEM fn cgu_generic_function[0]::bar[0]<u64>
//~ TRANS_ITEM fn cgu_generic_function[0]::foo[0]<u64>
//~ TRANS_ITEM fn cgu_generic_function::bar[0]<u64>
//~ TRANS_ITEM fn cgu_generic_function::foo[0]<u64>
let _ = cgu_generic_function::foo(2u64);
// This should not introduce a codegen item

View File

@ -29,31 +29,31 @@ fn main()
// Currently, no object code is generated for trait methods with default
// implemenations, unless they are actually called from somewhere. Therefore
// we cannot import the implementations and have to create our own inline.
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl[0]<u32>
//~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0]<u32>
let _ = Trait::with_default_impl(0u32);
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl[0]<char>
//~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0]<char>
let _ = Trait::with_default_impl('c');
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0]<u32, &str>
//~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0]<u32, &str>
let _ = Trait::with_default_impl_generic(0u32, "abc");
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0]<u32, bool>
//~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0]<u32, bool>
let _ = Trait::with_default_impl_generic(0u32, false);
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0]<char, i16>
//~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0]<char, i16>
let _ = Trait::with_default_impl_generic('x', 1i16);
//~ TRANS_ITEM fn cgu_export_trait_method[0]::Trait[0]::with_default_impl_generic[0]<char, i32>
//~ TRANS_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0]<char, i32>
let _ = Trait::with_default_impl_generic('y', 0i32);
//~ TRANS_ITEM fn cgu_export_trait_method[0]::u32.Trait[0]::without_default_impl_generic[0]<char>
//~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0]<char>
let _: (u32, char) = Trait::without_default_impl_generic('c');
//~ TRANS_ITEM fn cgu_export_trait_method[0]::u32.Trait[0]::without_default_impl_generic[0]<bool>
//~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0]<bool>
let _: (u32, bool) = Trait::without_default_impl_generic(false);
//~ TRANS_ITEM fn cgu_export_trait_method[0]::char.Trait[0]::without_default_impl_generic[0]<char>
//~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0]<char>
let _: (char, char) = Trait::without_default_impl_generic('c');
//~ TRANS_ITEM fn cgu_export_trait_method[0]::char.Trait[0]::without_default_impl_generic[0]<bool>
//~ TRANS_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0]<bool>
let _: (char, bool) = Trait::without_default_impl_generic(false);
}

View File

@ -49,17 +49,17 @@ struct NonGenericWithDrop(i32);
impl Drop for NonGenericWithDrop {
fn drop(&mut self) {}
//~ TRANS_ITEM fn generic_drop_glue::NonGenericWithDrop.Drop[0]::drop[0]
//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0]
}
//~ TRANS_ITEM fn generic_drop_glue::main[0]
fn main() {
//~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0]<i8, char>
//~ TRANS_ITEM fn generic_drop_glue::StructWithDrop<T1, T2>.Drop[0]::drop[0]<i8, char>
//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<i8, char>
let _ = StructWithDrop { x: 0i8, y: 'a' }.x;
//~ TRANS_ITEM drop-glue generic_drop_glue::StructWithDrop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
//~ TRANS_ITEM fn generic_drop_glue::StructWithDrop<T1, T2>.Drop[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]>
let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y;
// Should produce no drop glue
@ -71,14 +71,14 @@ fn main() {
let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y;
//~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0]<i32, i64>
//~ TRANS_ITEM fn generic_drop_glue::EnumWithDrop<T1, T2>.Drop[0]::drop[0]<i32, i64>
//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<i32, i64>
let _ = match EnumWithDrop::A::<i32, i64>(0) {
EnumWithDrop::A(x) => x,
EnumWithDrop::B(x) => x as i32
};
//~ TRANS_ITEM drop-glue generic_drop_glue::EnumWithDrop[0]<f64, f32>
//~ TRANS_ITEM fn generic_drop_glue::EnumWithDrop<T1, T2>.Drop[0]::drop[0]<f64, f32>
//~ TRANS_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0]<f64, f32>
let _ = match EnumWithDrop::B::<f64, f32>(1.0) {
EnumWithDrop::A(x) => x,
EnumWithDrop::B(x) => x as f64

View File

@ -40,11 +40,11 @@ pub struct LifeTimeOnly<'a> {
impl<'a> LifeTimeOnly<'a> {
//~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::foo[0]
//~ TRANS_ITEM fn generic_impl::{{impl}}[1]::foo[0]
pub fn foo(&self) {}
//~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::bar[0]
//~ TRANS_ITEM fn generic_impl::{{impl}}[1]::bar[0]
pub fn bar(&'a self) {}
//~ TRANS_ITEM fn generic_impl::LifeTimeOnly<'a>[0]::baz[0]
//~ TRANS_ITEM fn generic_impl::{{impl}}[1]::baz[0]
pub fn baz<'b>(&'b self) {}
pub fn non_instantiated<T>(&self) {}
@ -53,27 +53,27 @@ impl<'a> LifeTimeOnly<'a> {
//~ TRANS_ITEM fn generic_impl::main[0]
fn main() {
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::new[0]<i32>
//~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]<i32>
//~ TRANS_ITEM fn generic_impl::id[0]<i32>
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::get[0]<i32, i16>
//~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0]<i32, i16>
let _ = Struct::new(0i32).get(0i16);
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::new[0]<i64>
//~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]<i64>
//~ TRANS_ITEM fn generic_impl::id[0]<i64>
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::get[0]<i64, i16>
//~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0]<i64, i16>
let _ = Struct::new(0i64).get(0i16);
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::new[0]<char>
//~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]<char>
//~ TRANS_ITEM fn generic_impl::id[0]<char>
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::get[0]<char, i16>
//~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0]<char, i16>
let _ = Struct::new('c').get(0i16);
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::new[0]<&str>
//~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]<&str>
//~ TRANS_ITEM fn generic_impl::id[0]<&str>
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::get[0]<generic_impl::Struct[0]<&str>, i16>
//~ TRANS_ITEM fn generic_impl::{{impl}}[0]::get[0]<generic_impl::Struct[0]<&str>, i16>
let _ = Struct::new(Struct::new("str")).get(0i16);
//~ TRANS_ITEM fn generic_impl::Struct<T>[0]::new[0]<generic_impl::Struct[0]<&str>>
//~ TRANS_ITEM fn generic_impl::{{impl}}[0]::new[0]<generic_impl::Struct[0]<&str>>
//~ TRANS_ITEM fn generic_impl::id[0]<generic_impl::Struct[0]<&str>>
let _ = (Struct::new(Struct::new("str")).f)(Struct::new("str"));
}

View File

@ -21,7 +21,7 @@ trait SomeTrait {
// discovered.
pub fn generic_function<T>(x: T) -> (T, i32) {
impl SomeTrait for i64 {
//~ TRANS_ITEM fn impl_in_non_instantiated_generic::generic_function[0]::i64.SomeTrait[0]::foo[0]
//~ TRANS_ITEM fn impl_in_non_instantiated_generic::generic_function[0]::{{impl}}[0]::foo[0]
fn foo(&self) {}
}

View File

@ -31,12 +31,12 @@ impl<T> Trait for Struct<T> {
fn main() {
let s1 = Struct { _a: 0u32 };
//~ TRANS_ITEM fn instantiation_through_vtable::Struct<T>.Trait[0]::foo[0]<u32>
//~ TRANS_ITEM fn instantiation_through_vtable::Struct<T>.Trait[0]::bar[0]<u32>
//~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u32>
//~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u32>
let _ = &s1 as &Trait;
let s1 = Struct { _a: 0u64 };
//~ TRANS_ITEM fn instantiation_through_vtable::Struct<T>.Trait[0]::foo[0]<u64>
//~ TRANS_ITEM fn instantiation_through_vtable::Struct<T>.Trait[0]::bar[0]<u64>
//~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0]<u64>
//~ TRANS_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0]<u64>
let _ = &s1 as &Trait;
}

View File

@ -19,7 +19,7 @@ struct StructWithDrop {
}
impl Drop for StructWithDrop {
//~ TRANS_ITEM fn non_generic_drop_glue::StructWithDrop.Drop[0]::drop[0]
//~ TRANS_ITEM fn non_generic_drop_glue::{{impl}}[0]::drop[0]
fn drop(&mut self) {}
}
@ -33,7 +33,7 @@ enum EnumWithDrop {
}
impl Drop for EnumWithDrop {
//~ TRANS_ITEM fn non_generic_drop_glue::EnumWithDrop.Drop[0]::drop[0]
//~ TRANS_ITEM fn non_generic_drop_glue::{{impl}}[1]::drop[0]
fn drop(&mut self) {}
}

View File

@ -38,31 +38,31 @@ fn bar() {
struct Struct { _x: i32 }
impl Struct {
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0]
//~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]
fn foo() {
{
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0]::foo[0]
//~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[0]
fn foo() {}
foo();
}
{
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::foo[0]::foo[1]
//~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[1]
fn foo() {}
foo();
}
}
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0]
//~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]
fn bar(&self) {
{
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0]::foo[0]
//~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[0]
fn foo() {}
foo();
}
{
//~ TRANS_ITEM fn non_generic_functions::Struct[0]::bar[0]::foo[1]
//~ TRANS_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[1]
fn foo() {}
foo();
}

View File

@ -23,7 +23,7 @@ pub struct Indexable {
impl Index<usize> for Indexable {
type Output = u8;
//~ TRANS_ITEM fn overloaded_operators::Indexable.Index<usize>[0]::index[0]
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[0]::index[0]
fn index(&self, index: usize) -> &Self::Output {
if index >= 3 {
&self.data[0]
@ -34,7 +34,7 @@ impl Index<usize> for Indexable {
}
impl IndexMut<usize> for Indexable {
//~ TRANS_ITEM fn overloaded_operators::Indexable.IndexMut<usize>[0]::index_mut[0]
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[1]::index_mut[0]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
if index >= 3 {
&mut self.data[0]
@ -45,8 +45,8 @@ impl IndexMut<usize> for Indexable {
}
//~ TRANS_ITEM fn overloaded_operators::Equatable.::std::cmp::PartialEq[0]::eq[0]
//~ TRANS_ITEM fn overloaded_operators::Equatable.::std::cmp::PartialEq[0]::ne[0]
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::eq[0]
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[2]::ne[0]
#[derive(PartialEq)]
pub struct Equatable(u32);
@ -54,7 +54,7 @@ pub struct Equatable(u32);
impl Add<u32> for Equatable {
type Output = u32;
//~ TRANS_ITEM fn overloaded_operators::Equatable.Add<u32>[0]::add[0]
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[3]::add[0]
fn add(self, rhs: u32) -> u32 {
self.0 + rhs
}
@ -63,7 +63,7 @@ impl Add<u32> for Equatable {
impl Deref for Equatable {
type Target = u32;
//~ TRANS_ITEM fn overloaded_operators::Equatable.Deref[0]::deref[0]
//~ TRANS_ITEM fn overloaded_operators::{{impl}}[4]::deref[0]
fn deref(&self) -> &Self::Target {
&self.0
}

View File

@ -20,7 +20,7 @@ pub trait SomeTrait {
impl SomeTrait for i64 {
//~ TRANS_ITEM fn trait_implementations::i64.SomeTrait[0]::foo[0]
//~ TRANS_ITEM fn trait_implementations::{{impl}}[0]::foo[0]
fn foo(&self) {}
fn bar<T>(&self, _: T) {}
@ -28,7 +28,7 @@ impl SomeTrait for i64 {
impl SomeTrait for i32 {
//~ TRANS_ITEM fn trait_implementations::i32.SomeTrait[0]::foo[0]
//~ TRANS_ITEM fn trait_implementations::{{impl}}[1]::foo[0]
fn foo(&self) {}
fn bar<T>(&self, _: T) {}
@ -42,7 +42,7 @@ pub trait SomeGenericTrait<T> {
// Concrete impl of generic trait
impl SomeGenericTrait<u32> for f64 {
//~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait<u32>[0]::foo[0]
//~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::foo[0]
fn foo(&self, _: u32) {}
fn bar<T2>(&self, _: u32, _: T2) {}
@ -57,25 +57,25 @@ impl<T> SomeGenericTrait<T> for f32 {
//~ TRANS_ITEM fn trait_implementations::main[0]
fn main() {
//~ TRANS_ITEM fn trait_implementations::i32.SomeTrait[0]::bar[0]<char>
//~ TRANS_ITEM fn trait_implementations::{{impl}}[1]::bar[0]<char>
0i32.bar('x');
//~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait<u32>[0]::bar[0]<&str>
//~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<&str>
0f64.bar(0u32, "&str");
//~ TRANS_ITEM fn trait_implementations::f64.SomeGenericTrait<u32>[0]::bar[0]<()>
//~ TRANS_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<()>
0f64.bar(0u32, ());
//~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait<T>[0]::foo[0]<char>
//~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::foo[0]<char>
0f32.foo('x');
//~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait<T>[0]::foo[0]<i64>
//~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::foo[0]<i64>
0f32.foo(-1i64);
//~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait<T>[0]::bar[0]<u32, ()>
//~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::bar[0]<u32, ()>
0f32.bar(0u32, ());
//~ TRANS_ITEM fn trait_implementations::f32.SomeGenericTrait<T>[0]::bar[0]<&str, &str>
//~ TRANS_ITEM fn trait_implementations::{{impl}}[3]::bar[0]<&str, &str>
0f32.bar("&str", "&str");
}

View File

@ -39,7 +39,7 @@ fn take_foo_mut<T, F: FnMut(T) -> T>(mut f: F, arg: T) -> T {
//~ TRANS_ITEM fn trait_method_as_argument::main[0]
fn main() {
//~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0]<u32, fn(u32) -> u32>
//~ TRANS_ITEM fn trait_method_as_argument::u32.Trait[0]::foo[0]
//~ TRANS_ITEM fn trait_method_as_argument::{{impl}}[0]::foo[0]
take_foo_once(Trait::foo, 0u32);
//~ TRANS_ITEM fn trait_method_as_argument::take_foo_once[0]<char, fn(char) -> char>

View File

@ -21,7 +21,7 @@ struct Intermediate(Leaf);
struct Leaf;
impl Drop for Leaf {
//~ TRANS_ITEM fn transitive_drop_glue::Leaf.Drop[0]::drop[0]
//~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[0]::drop[0]
fn drop(&mut self) {}
}
@ -44,12 +44,12 @@ fn main() {
//~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0]<u32>
//~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0]<u32>
//~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0]<u32>
//~ TRANS_ITEM fn transitive_drop_glue::LeafGen<T>.Drop[0]::drop[0]<u32>
//~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<u32>
let _ = RootGen(IntermediateGen(LeafGen(0u32)));
//~ TRANS_ITEM drop-glue transitive_drop_glue::RootGen[0]<i16>
//~ TRANS_ITEM drop-glue transitive_drop_glue::IntermediateGen[0]<i16>
//~ TRANS_ITEM drop-glue transitive_drop_glue::LeafGen[0]<i16>
//~ TRANS_ITEM fn transitive_drop_glue::LeafGen<T>.Drop[0]::drop[0]<i16>
//~ TRANS_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0]<i16>
let _ = RootGen(IntermediateGen(LeafGen(0i16)));
}

View File

@ -17,7 +17,7 @@
struct Dropped;
impl Drop for Dropped {
//~ TRANS_ITEM fn tuple_drop_glue::Dropped.Drop[0]::drop[0]
//~ TRANS_ITEM fn tuple_drop_glue::{{impl}}[0]::drop[0]
fn drop(&mut self) {}
}

View File

@ -57,11 +57,11 @@ fn main()
{
// simple case
let bool_sized = &true;
//~ TRANS_ITEM fn unsizing::bool.Trait[0]::foo[0]
//~ TRANS_ITEM fn unsizing::{{impl}}[0]::foo[0]
let _bool_unsized = bool_sized as &Trait;
let char_sized = &true;
//~ TRANS_ITEM fn unsizing::char.Trait[0]::foo[0]
//~ TRANS_ITEM fn unsizing::{{impl}}[1]::foo[0]
let _char_unsized = char_sized as &Trait;
// struct field
@ -70,11 +70,11 @@ fn main()
_b: 2,
_c: 3.0f64
};
//~ TRANS_ITEM fn unsizing::f64.Trait[0]::foo[0]
//~ TRANS_ITEM fn unsizing::{{impl}}[2]::foo[0]
let _struct_unsized = struct_sized as &Struct<Trait>;
// custom coercion
let wrapper_sized = Wrapper(&0u32);
//~ TRANS_ITEM fn unsizing::u32.Trait[0]::foo[0]
//~ TRANS_ITEM fn unsizing::{{impl}}[3]::foo[0]
let _wrapper_sized = wrapper_sized as Wrapper<Trait>;
}

View File

@ -85,5 +85,5 @@ impl NonGeneric {
}
// Only the non-generic methods should be instantiated:
//~ TRANS_ITEM fn unused_traits_and_generics::NonGeneric[0]::foo[0]
//~ TRANS_ITEM fn unused_traits_and_generics::{{impl}}[3]::foo[0]
//~ TRANS_ITEM drop-glue i8

View File

@ -0,0 +1,16 @@
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_attrs)]
#[rustc_symbol_name] //~ ERROR _ZN5basic4main
#[rustc_item_path] //~ ERROR item-path(main)
fn main() {
}

View File

@ -0,0 +1,35 @@
// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(rustc_attrs)]
#![allow(dead_code)]
mod foo {
pub struct Foo { x: u32 }
impl Foo {
#[rustc_symbol_name] //~ ERROR _ZN5impl13foo3Foo3bar
#[rustc_item_path] //~ ERROR item-path(foo::Foo::bar)
fn bar() { }
}
}
mod bar {
use foo::Foo;
impl Foo {
#[rustc_symbol_name] //~ ERROR _ZN5impl13bar26_$LT$impl$u20$foo..Foo$GT$3baz
#[rustc_item_path] //~ ERROR item-path(bar::<impl foo::Foo>::baz)
fn baz() { }
}
}
fn main() {
}

View File

@ -41,37 +41,37 @@ pub fn bar() {
((::std::fmt::format as
fn(core::fmt::Arguments<'_>) -> collections::string::String {collections::fmt::format})(((::std::fmt::Arguments::new_v1
as
fn(&[&str], &[core::fmt::ArgumentV1<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'a><'_>::new_v1})(({
static __STATIC_FMTSTR:
&'static [&'static str]
=
(&([("test"
as
&'static str)]
as
[&'static str; 1])
fn(&[&str], &[core::fmt::ArgumentV1<'_>]) -> core::fmt::Arguments<'_> {core::fmt::Arguments<'_>::new_v1})(({
static __STATIC_FMTSTR:
&'static [&'static str]
=
(&([("test"
as
&'static [&'static str; 1]);
(__STATIC_FMTSTR
as
&'static [&'static str])
}
as
&[&str]),
(&(match (()
as
())
{
()
=>
([]
&'static str)]
as
[core::fmt::ArgumentV1<'_>; 0]),
}
as
[core::fmt::ArgumentV1<'_>; 0])
as
&[core::fmt::ArgumentV1<'_>; 0]))
[&'static str; 1])
as
&'static [&'static str; 1]);
(__STATIC_FMTSTR
as
&'static [&'static str])
}
as
&[&str]),
(&(match (()
as
())
{
()
=>
([]
as
[core::fmt::ArgumentV1<'_>; 0]),
}
as
[core::fmt::ArgumentV1<'_>; 0])
as
&[core::fmt::ArgumentV1<'_>; 0]))
as
core::fmt::Arguments<'_>))
as collections::string::String);

View File

@ -0,0 +1,12 @@
-include ../tools.mk
# Test that if we build `b` against a version of `a` that has one set
# of types, it will not run with a dylib that has a different set of
# types.
all:
$(RUSTC) a.rs --cfg x -C prefer-dynamic
$(RUSTC) b.rs -C prefer-dynamic
$(call RUN,b)
$(RUSTC) a.rs --cfg y -C prefer-dynamic
$(call FAIL,b)

View File

@ -0,0 +1,20 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_name = "a"]
#![crate_type = "dylib"]
#[cfg(x)]
pub fn foo(x: u32) { }
#[cfg(y)]
pub fn foo(x: i32) { }

View File

@ -0,0 +1,17 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_name = "b"]
extern crate a;
fn main() {
a::foo(22_u32);
}

View File

@ -1,5 +1,5 @@
-include ../tools.mk
all:
$(RUSTC) libc.rs
$(RUSTC) libc.rs -Cmetadata=foo
$(RUSTC) main.rs --extern libc=$(TMPDIR)/liblibc.rlib

View File

@ -12,7 +12,7 @@ time: libc
libc:
mkdir -p $(OUT)/libc
$(RUSTC) in/libc/lib.rs --crate-name=libc -o $(OUT)/libc/liblibc.rlib
$(RUSTC) in/libc/lib.rs --crate-name=libc -Cmetadata=foo -o $(OUT)/libc/liblibc.rlib
else
all:
endif

View File

@ -7,8 +7,7 @@ all: others
$(RUSTC) -C relocation-model=default foo.rs
$(call RUN,foo)
$(RUSTC) -C relocation-model=default --crate-type=dylib foo.rs
$(RUSTC) -C relocation-model=dynamic-no-pic --crate-type=dylib foo.rs
$(RUSTC) -C relocation-model=dynamic-no-pic --crate-type=dylib foo.rs --emit=link,obj
ifdef IS_MSVC
# FIXME(#28026)
@ -17,5 +16,4 @@ else
others:
$(RUSTC) -C relocation-model=static foo.rs
$(call RUN,foo)
$(RUSTC) -C relocation-model=static --crate-type=dylib foo.rs
endif

View File

@ -0,0 +1,20 @@
-include ../tools.mk
all:
$(RUSTC) reproducible-build-aux.rs
$(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build1"
$(RUSTC) reproducible-build.rs -o"$(TMPDIR)/reproducible-build2"
nm "$(TMPDIR)/reproducible-build1" | sort > "$(TMPDIR)/reproducible-build1.nm"
nm "$(TMPDIR)/reproducible-build2" | sort > "$(TMPDIR)/reproducible-build2.nm"
cmp "$(TMPDIR)/reproducible-build1.nm" "$(TMPDIR)/reproducible-build2.nm" || exit 1
$(RUSTC) reproducible-build-aux.rs -g
$(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build1-debug"
$(RUSTC) reproducible-build.rs -g -o"$(TMPDIR)/reproducible-build2-debug"
nm "$(TMPDIR)/reproducible-build1-debug" | sort > "$(TMPDIR)/reproducible-build1-debug.nm"
nm "$(TMPDIR)/reproducible-build2-debug" | sort > "$(TMPDIR)/reproducible-build2-debug.nm"
cmp "$(TMPDIR)/reproducible-build1-debug.nm" "$(TMPDIR)/reproducible-build2-debug.nm" || exit 1
$(RUSTC) reproducible-build-aux.rs -O
$(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build1-opt"
$(RUSTC) reproducible-build.rs -O -o"$(TMPDIR)/reproducible-build2-opt"
nm "$(TMPDIR)/reproducible-build1-opt" | sort > "$(TMPDIR)/reproducible-build1-opt.nm"
nm "$(TMPDIR)/reproducible-build2-opt" | sort > "$(TMPDIR)/reproducible-build2-opt.nm"
cmp "$(TMPDIR)/reproducible-build1-opt.nm" "$(TMPDIR)/reproducible-build2-opt.nm" || exit 1

View File

@ -0,0 +1,38 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_type="lib"]
pub static STATIC: i32 = 1234;
pub struct Struct<T1, T2> {
_t1: std::marker::PhantomData<T1>,
_t2: std::marker::PhantomData<T2>,
}
pub fn regular_fn(_: i32) {}
pub fn generic_fn<T1, T2>() {}
impl<T1, T2> Drop for Struct<T1, T2> {
fn drop(&mut self) {}
}
pub enum Enum {
Variant1,
Variant2(u32),
Variant3 { x: u32 }
}
pub struct TupleStruct(pub i8, pub i16, pub i32, pub i64);
pub trait Trait<T1, T2> {
fn foo(&self);
}

View File

@ -0,0 +1,128 @@
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// This test case makes sure that two identical invocations of the compiler
// (i.e. same code base, same compile-flags, same compiler-versions, etc.)
// produce the same output. In the past, symbol names of monomorphized functions
// were not deterministic (which we want to avoid).
//
// The test tries to exercise as many different paths into symbol name
// generation as possible:
//
// - regular functions
// - generic functions
// - methods
// - statics
// - closures
// - enum variant constructors
// - tuple struct constructors
// - drop glue
// - FnOnce adapters
// - Trait object shims
// - Fn Pointer shims
#![allow(dead_code)]
extern crate reproducible_build_aux;
static STATIC: i32 = 1234;
pub struct Struct<T1, T2> {
x: T1,
y: T2,
}
fn regular_fn(_: i32) {}
fn generic_fn<T1, T2>() {}
impl<T1, T2> Drop for Struct<T1, T2> {
fn drop(&mut self) {}
}
pub enum Enum {
Variant1,
Variant2(u32),
Variant3 { x: u32 }
}
struct TupleStruct(i8, i16, i32, i64);
impl TupleStruct {
pub fn bar(&self) {}
}
trait Trait<T1, T2> {
fn foo(&self);
}
impl Trait<i32, u64> for u64 {
fn foo(&self) {}
}
impl reproducible_build_aux::Trait<char, String> for TupleStruct {
fn foo(&self) {}
}
fn main() {
regular_fn(STATIC);
generic_fn::<u32, char>();
generic_fn::<char, Struct<u32, u64>>();
generic_fn::<Struct<u64, u32>, reproducible_build_aux::Struct<u32, u64>>();
let dropped = Struct {
x: "",
y: 'a',
};
let _ = Enum::Variant1;
let _ = Enum::Variant2(0);
let _ = Enum::Variant3 { x: 0 };
let _ = TupleStruct(1, 2, 3, 4);
let closure = |x| {
x + 1i32
};
fn inner<F: Fn(i32) -> i32>(f: F) -> i32 {
f(STATIC)
}
println!("{}", inner(closure));
let object_shim: &Trait<i32, u64> = &0u64;
object_shim.foo();
fn with_fn_once_adapter<F: FnOnce(i32)>(f: F) {
f(0);
}
with_fn_once_adapter(|_:i32| { });
reproducible_build_aux::regular_fn(STATIC);
reproducible_build_aux::generic_fn::<u32, char>();
reproducible_build_aux::generic_fn::<char, Struct<u32, u64>>();
reproducible_build_aux::generic_fn::<Struct<u64, u32>,
reproducible_build_aux::Struct<u32, u64>>();
let _ = reproducible_build_aux::Enum::Variant1;
let _ = reproducible_build_aux::Enum::Variant2(0);
let _ = reproducible_build_aux::Enum::Variant3 { x: 0 };
let _ = reproducible_build_aux::TupleStruct(1, 2, 3, 4);
let object_shim: &reproducible_build_aux::Trait<char, String> = &TupleStruct(0, 1, 2, 3);
object_shim.foo();
let pointer_shim: &Fn(i32) = &regular_fn;
TupleStruct(1, 2, 3, 4).bar();
}

View File

@ -51,13 +51,29 @@ fn template(me: &str) -> Command {
return m;
}
fn expected(fn_name: &str) -> String {
// FIXME(#32481)
//
// On windows, we read the function name from debuginfo using some
// system APIs. For whatever reason, these APIs seem to use the
// "name" field, which is only the "relative" name, not the full
// name with namespace info, so we just see `foo` and not
// `backtrace::foo` as we see on linux (which uses the linkage
// name).
if cfg!(windows) && cfg!(target_env = "msvc") {
format!(" - {}", fn_name)
} else {
format!(" - backtrace::{}", fn_name)
}
}
fn runtest(me: &str) {
// Make sure that the stack trace is printed
let p = template(me).arg("fail").env("RUST_BACKTRACE", "1").spawn().unwrap();
let out = p.wait_with_output().unwrap();
assert!(!out.status.success());
let s = str::from_utf8(&out.stderr).unwrap();
assert!(s.contains("stack backtrace") && s.contains(" - foo"),
assert!(s.contains("stack backtrace") && s.contains(&expected("foo")),
"bad output: {}", s);
// Make sure the stack trace is *not* printed
@ -67,7 +83,7 @@ fn runtest(me: &str) {
let out = p.wait_with_output().unwrap();
assert!(!out.status.success());
let s = str::from_utf8(&out.stderr).unwrap();
assert!(!s.contains("stack backtrace") && !s.contains(" - foo"),
assert!(!s.contains("stack backtrace") && !s.contains(&expected("foo")),
"bad output2: {}", s);
// Make sure a stack trace is printed
@ -77,7 +93,7 @@ fn runtest(me: &str) {
let s = str::from_utf8(&out.stderr).unwrap();
// loosened the following from double::h to double:: due to
// spurious failures on mac, 32bit, optimized
assert!(s.contains("stack backtrace") && s.contains(" - double"),
assert!(s.contains("stack backtrace") && s.contains(&expected("double")),
"bad output3: {}", s);
// Make sure a stack trace isn't printed too many times

View File

@ -9,8 +9,6 @@
// except according to those terms.
// ignore-windows - this is a unix-specific test
// no-prefer-dynamic - this test breaks with dynamic linking as
// some LD_LIBRARY_PATH entries are relative and it cd's to /.
#![feature(process_exec, libc)]

View File

@ -8,13 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:issue-17718.rs
// aux-build:issue-17718-aux.rs
#![feature(core)]
#![feature(const_fn)]
extern crate issue_17718 as other;
extern crate issue_17718_aux as other;
use std::sync::atomic::{AtomicUsize, Ordering};

View File

@ -8,13 +8,13 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:typeid-intrinsic.rs
// aux-build:typeid-intrinsic2.rs
// aux-build:typeid-intrinsic-aux1.rs
// aux-build:typeid-intrinsic-aux2.rs
#![feature(core_intrinsics)]
extern crate typeid_intrinsic as other1;
extern crate typeid_intrinsic2 as other2;
extern crate typeid_intrinsic_aux1 as other1;
extern crate typeid_intrinsic_aux2 as other2;
use std::hash::{SipHasher, Hasher, Hash};
use std::any::TypeId;