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:
commit
8d2d2be6c6
@ -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))
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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(),
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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!() }
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
317
src/librustc/middle/ty/item_path.rs
Normal file
317
src/librustc/middle/ty/item_path.rs
Normal 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);
|
||||
}
|
||||
}
|
@ -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))
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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!("{}",
|
||||
|
@ -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,
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 => ()
|
||||
|
@ -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>)>
|
||||
|
@ -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")
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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![],
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -359,6 +359,7 @@ impl<'a> Linker for MsvcLinker<'a> {
|
||||
for symbol in symbols {
|
||||
writeln!(f, " {}", symbol)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})();
|
||||
if let Err(e) = res {
|
||||
|
378
src/librustc_trans/back/symbol_names.rs
Normal file
378
src/librustc_trans/back/symbol_names.rs
Normal 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
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
});
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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 &&
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
86
src/librustc_trans/trans/symbol_names_test.rs
Normal file
86
src/librustc_trans/trans/symbol_names_test.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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"),
|
||||
|
@ -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) {}
|
||||
|
@ -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) {}
|
||||
|
@ -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
|
||||
|
@ -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")]
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {}
|
||||
|
@ -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 {
|
||||
|
@ -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 {}
|
||||
|
@ -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() {}
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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"));
|
||||
}
|
||||
|
@ -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) {}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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) {}
|
||||
}
|
||||
|
||||
|
@ -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>;
|
||||
}
|
||||
|
@ -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
|
||||
|
16
src/test/compile-fail/symbol-names/basic.rs
Normal file
16
src/test/compile-fail/symbol-names/basic.rs
Normal 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() {
|
||||
}
|
35
src/test/compile-fail/symbol-names/impl1.rs
Normal file
35
src/test/compile-fail/symbol-names/impl1.rs
Normal 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() {
|
||||
}
|
@ -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);
|
||||
|
12
src/test/run-make/a-b-a-linker-guard/Makefile
Normal file
12
src/test/run-make/a-b-a-linker-guard/Makefile
Normal 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)
|
20
src/test/run-make/a-b-a-linker-guard/a.rs
Normal file
20
src/test/run-make/a-b-a-linker-guard/a.rs
Normal 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) { }
|
||||
|
||||
|
17
src/test/run-make/a-b-a-linker-guard/b.rs
Normal file
17
src/test/run-make/a-b-a-linker-guard/b.rs
Normal 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);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
-include ../tools.mk
|
||||
|
||||
all:
|
||||
$(RUSTC) libc.rs
|
||||
$(RUSTC) libc.rs -Cmetadata=foo
|
||||
$(RUSTC) main.rs --extern libc=$(TMPDIR)/liblibc.rlib
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
20
src/test/run-make/reproducible-build/Makefile
Normal file
20
src/test/run-make/reproducible-build/Makefile
Normal 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
|
@ -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);
|
||||
}
|
128
src/test/run-make/reproducible-build/reproducible-build.rs
Normal file
128
src/test/run-make/reproducible-build/reproducible-build.rs
Normal 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) = ®ular_fn;
|
||||
|
||||
TupleStruct(1, 2, 3, 4).bar();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)]
|
||||
|
||||
|
@ -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};
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user