提交 5b093eba 编写于 作者: M Michael Woerister

Make names of types used in LLVM IR stable.

Before this PR, type names could depend on the cratenum being used
for a given crate and also on the source location of closures.
Both are undesirable for incremental compilation where we cache
LLVM IR and don't want it to depend on formatting or in which
order crates are loaded.
上级 876b7610
// 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.
/// Convert unsigned integers into a string representation with some base.
/// Bases up to and including 36 can be used for case-insensitive things.
use std::str;
pub const MAX_BASE: u64 = 64;
const BASE_64: &'static [u8; MAX_BASE as usize] =
b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@$";
#[inline]
pub fn push_str(mut n: u64, base: u64, output: &mut String) {
debug_assert!(base >= 2 && base <= MAX_BASE);
let mut s = [0u8; 64];
let mut index = 0;
loop {
s[index] = BASE_64[(n % base) as usize];
index += 1;
n /= base;
if n == 0 {
break;
}
}
&mut s[0..index].reverse();
output.push_str(str::from_utf8(&s[0..index]).unwrap());
}
#[inline]
pub fn encode(n: u64, base: u64) -> String {
let mut s = String::with_capacity(13);
push_str(n, base, &mut s);
s
}
#[test]
fn test_encode() {
fn test(n: u64, base: u64) {
assert_eq!(Ok(n), u64::from_str_radix(&encode(n, base)[..], base as u32));
}
for base in 2..37 {
test(0, base);
test(1, base);
test(35, base);
test(36, base);
test(37, base);
test(u64::max_value(), base);
for i in 0 .. 1_000 {
test(i * 983, base);
}
}
}
......@@ -47,6 +47,7 @@
pub mod array_vec;
pub mod accumulate_vec;
pub mod small_vec;
pub mod base_n;
pub mod bitslice;
pub mod blake2b;
pub mod bitvec;
......
......@@ -119,7 +119,7 @@
use rustc::session::Session;
use rustc::ty::TyCtxt;
use rustc::util::fs as fs_util;
use rustc_data_structures::flock;
use rustc_data_structures::{flock, base_n};
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use std::ffi::OsString;
......@@ -135,6 +135,12 @@
const WORK_PRODUCTS_FILENAME: &'static str = "work-products.bin";
const METADATA_HASHES_FILENAME: &'static str = "metadata.bin";
// We encode integers using the following base, so they are shorter than decimal
// or hexadecimal numbers (we want short file and directory names). Since these
// numbers will be used in file names, we choose an encoding that is not
// case-sensitive (as opposed to base64, for example).
const INT_ENCODE_BASE: u64 = 36;
pub fn dep_graph_path(sess: &Session) -> PathBuf {
in_incr_comp_dir_sess(sess, DEP_GRAPH_FILENAME)
}
......@@ -327,7 +333,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Svh) {
let mut new_sub_dir_name = String::from(&old_sub_dir_name[.. dash_indices[2] + 1]);
// Append the svh
new_sub_dir_name.push_str(&encode_base_36(svh.as_u64()));
base_n::push_str(svh.as_u64(), INT_ENCODE_BASE, &mut new_sub_dir_name);
// Create the full path
let new_path = incr_comp_session_dir.parent().unwrap().join(new_sub_dir_name);
......@@ -433,7 +439,8 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf {
let directory_name = format!("s-{}-{}-working",
timestamp,
encode_base_36(random_number as u64));
base_n::encode(random_number as u64,
INT_ENCODE_BASE));
debug!("generate_session_dir_path: directory_name = {}", directory_name);
let directory_path = crate_dir.join(directory_name);
debug!("generate_session_dir_path: directory_path = {}", directory_path.display());
......@@ -562,27 +569,11 @@ fn extract_timestamp_from_session_dir(directory_name: &str)
string_to_timestamp(&directory_name[dash_indices[0]+1 .. dash_indices[1]])
}
const BASE_36: &'static [u8] = b"0123456789abcdefghijklmnopqrstuvwxyz";
fn encode_base_36(mut n: u64) -> String {
let mut s = Vec::with_capacity(13);
loop {
s.push(BASE_36[(n % 36) as usize]);
n /= 36;
if n == 0 {
break;
}
}
s.reverse();
String::from_utf8(s).unwrap()
}
fn timestamp_to_string(timestamp: SystemTime) -> String {
let duration = timestamp.duration_since(UNIX_EPOCH).unwrap();
let micros = duration.as_secs() * 1_000_000 +
(duration.subsec_nanos() as u64) / 1000;
encode_base_36(micros)
base_n::encode(micros, INT_ENCODE_BASE)
}
fn string_to_timestamp(s: &str) -> Result<SystemTime, ()> {
......@@ -629,7 +620,7 @@ pub fn find_metadata_hashes_for(tcx: TyCtxt, cnum: CrateNum) -> Option<PathBuf>
};
let target_svh = tcx.sess.cstore.crate_hash(cnum);
let target_svh = encode_base_36(target_svh.as_u64());
let target_svh = base_n::encode(target_svh.as_u64(), INT_ENCODE_BASE);
let sub_dir = find_metadata_hashes_iter(&target_svh, dir_entries.filter_map(|e| {
e.ok().map(|e| e.file_name().to_string_lossy().into_owned())
......@@ -677,7 +668,9 @@ fn crate_path(sess: &Session,
let mut hasher = DefaultHasher::new();
crate_disambiguator.hash(&mut hasher);
let crate_name = format!("{}-{}", crate_name, encode_base_36(hasher.finish()));
let crate_name = format!("{}-{}",
crate_name,
base_n::encode(hasher.finish(), INT_ENCODE_BASE));
incr_dir.join(crate_name)
}
......@@ -1049,21 +1042,3 @@ fn test_find_metadata_hashes_iter()
None
);
}
#[test]
fn test_encode_base_36() {
fn test(n: u64) {
assert_eq!(Ok(n), u64::from_str_radix(&encode_base_36(n)[..], 36));
}
test(0);
test(1);
test(35);
test(36);
test(37);
test(u64::max_value());
for i in 0 .. 1_000 {
test(i * 983);
}
}
......@@ -74,7 +74,7 @@
use partitioning::{self, PartitioningStrategy, CodegenUnit};
use symbol_map::SymbolMap;
use symbol_names_test;
use trans_item::TransItem;
use trans_item::{TransItem, DefPathBasedNames};
use type_::Type;
use type_of;
use value::Value;
......@@ -1004,7 +1004,15 @@ pub fn build_return_block(&self, ret_cx: Block<'blk, 'tcx>,
}
pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) {
let _s = StatRecorder::new(ccx, ccx.tcx().item_path_str(instance.def));
let _s = if ccx.sess().trans_stats() {
let mut instance_name = String::new();
DefPathBasedNames::new(ccx.tcx(), true, true)
.push_def_path(instance.def, &mut instance_name);
Some(StatRecorder::new(ccx, instance_name))
} else {
None
};
// this is an info! to allow collecting monomorphization statistics
// and to allow finding the last function before LLVM aborts from
// release builds.
......
......@@ -213,7 +213,7 @@
use monomorphize::{self, Instance};
use util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
use trans_item::{TransItem, type_to_string, def_id_to_string};
use trans_item::{TransItem, DefPathBasedNames};
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum TransItemCollectionMode {
......@@ -1234,3 +1234,21 @@ fn visit_mir_and_promoted<'tcx, V: MirVisitor<'tcx>>(mut visitor: V, mir: &mir::
visitor.visit_mir(promoted);
}
}
fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> String {
let mut output = String::new();
let printer = DefPathBasedNames::new(tcx, false, false);
printer.push_def_path(def_id, &mut output);
output
}
fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: ty::Ty<'tcx>)
-> String {
let mut output = String::new();
let printer = DefPathBasedNames::new(tcx, false, false);
printer.push_type_name(ty, &mut output);
output
}
......@@ -26,6 +26,7 @@
use partitioning::CodegenUnit;
use trans_item::TransItem;
use type_::Type;
use rustc_data_structures::base_n;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
use session::config::NoDebugInfo;
......@@ -975,7 +976,11 @@ pub fn generate_local_symbol_name(&self, prefix: &str) -> String {
self.local().local_gen_sym_counter.set(idx + 1);
// Include a '.' character, so there can be no accidental conflicts with
// user defined names
format!("{}.{}", prefix, idx)
let mut name = String::with_capacity(prefix.len() + 6);
name.push_str(prefix);
name.push_str(".");
base_n::push_str(idx as u64, base_n::MAX_BASE, &mut name);
name
}
}
......
......@@ -34,6 +34,7 @@
use glue;
use abi::{Abi, FnType};
use back::symbol_names;
use std::fmt::Write;
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
pub enum TransItem<'tcx> {
......@@ -307,7 +308,8 @@ pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
DropGlueKind::Ty(_) => s.push_str("drop-glue "),
DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "),
};
push_unique_type_name(tcx, dg.ty(), &mut s);
let printer = DefPathBasedNames::new(tcx, false, false);
printer.push_type_name(dg.ty(), &mut s);
s
}
TransItem::Fn(instance) => {
......@@ -326,7 +328,8 @@ fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-> String {
let mut result = String::with_capacity(32);
result.push_str(prefix);
push_instance_as_string(tcx, instance, &mut result);
let printer = DefPathBasedNames::new(tcx, false, false);
printer.push_instance_as_string(instance, &mut result);
result
}
}
......@@ -367,209 +370,219 @@ pub fn to_raw_string(&self) -> String {
/// Same as `unique_type_name()` but with the result pushed onto the given
/// `output` parameter.
pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
t: Ty<'tcx>,
output: &mut String) {
match t.sty {
ty::TyBool => output.push_str("bool"),
ty::TyChar => output.push_str("char"),
ty::TyStr => output.push_str("str"),
ty::TyNever => output.push_str("!"),
ty::TyInt(ast::IntTy::Is) => output.push_str("isize"),
ty::TyInt(ast::IntTy::I8) => output.push_str("i8"),
ty::TyInt(ast::IntTy::I16) => output.push_str("i16"),
ty::TyInt(ast::IntTy::I32) => output.push_str("i32"),
ty::TyInt(ast::IntTy::I64) => output.push_str("i64"),
ty::TyUint(ast::UintTy::Us) => output.push_str("usize"),
ty::TyUint(ast::UintTy::U8) => output.push_str("u8"),
ty::TyUint(ast::UintTy::U16) => output.push_str("u16"),
ty::TyUint(ast::UintTy::U32) => output.push_str("u32"),
ty::TyUint(ast::UintTy::U64) => output.push_str("u64"),
ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"),
ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
ty::TyAdt(adt_def, substs) => {
push_item_name(tcx, adt_def.did, output);
push_type_params(tcx, substs, &[], output);
},
ty::TyTuple(component_types) => {
output.push('(');
for &component_type in component_types {
push_unique_type_name(tcx, component_type, output);
output.push_str(", ");
}
if !component_types.is_empty() {
output.pop();
output.pop();
}
output.push(')');
},
ty::TyBox(inner_type) => {
output.push_str("Box<");
push_unique_type_name(tcx, inner_type, output);
output.push('>');
},
ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
output.push('*');
match mutbl {
hir::MutImmutable => output.push_str("const "),
hir::MutMutable => output.push_str("mut "),
}
pub struct DefPathBasedNames<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
omit_disambiguators: bool,
omit_local_crate_name: bool,
}
push_unique_type_name(tcx, inner_type, output);
},
ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => {
output.push('&');
if mutbl == hir::MutMutable {
output.push_str("mut ");
}
impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
omit_disambiguators: bool,
omit_local_crate_name: bool)
-> Self {
DefPathBasedNames {
tcx: tcx,
omit_disambiguators: omit_disambiguators,
omit_local_crate_name: omit_local_crate_name,
}
}
push_unique_type_name(tcx, inner_type, output);
},
ty::TyArray(inner_type, len) => {
output.push('[');
push_unique_type_name(tcx, inner_type, output);
output.push_str(&format!("; {}", len));
output.push(']');
},
ty::TySlice(inner_type) => {
output.push('[');
push_unique_type_name(tcx, inner_type, output);
output.push(']');
},
ty::TyTrait(ref trait_data) => {
push_item_name(tcx, trait_data.principal.def_id(), output);
push_type_params(tcx,
trait_data.principal.skip_binder().substs,
&trait_data.projection_bounds,
output);
},
ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
if unsafety == hir::Unsafety::Unsafe {
output.push_str("unsafe ");
}
pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String) {
match t.sty {
ty::TyBool => output.push_str("bool"),
ty::TyChar => output.push_str("char"),
ty::TyStr => output.push_str("str"),
ty::TyNever => output.push_str("!"),
ty::TyInt(ast::IntTy::Is) => output.push_str("isize"),
ty::TyInt(ast::IntTy::I8) => output.push_str("i8"),
ty::TyInt(ast::IntTy::I16) => output.push_str("i16"),
ty::TyInt(ast::IntTy::I32) => output.push_str("i32"),
ty::TyInt(ast::IntTy::I64) => output.push_str("i64"),
ty::TyUint(ast::UintTy::Us) => output.push_str("usize"),
ty::TyUint(ast::UintTy::U8) => output.push_str("u8"),
ty::TyUint(ast::UintTy::U16) => output.push_str("u16"),
ty::TyUint(ast::UintTy::U32) => output.push_str("u32"),
ty::TyUint(ast::UintTy::U64) => output.push_str("u64"),
ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"),
ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
ty::TyAdt(adt_def, substs) => {
self.push_def_path(adt_def.did, output);
self.push_type_params(substs, &[], output);
},
ty::TyTuple(component_types) => {
output.push('(');
for &component_type in component_types {
self.push_type_name(component_type, output);
output.push_str(", ");
}
if !component_types.is_empty() {
output.pop();
output.pop();
}
output.push(')');
},
ty::TyBox(inner_type) => {
output.push_str("Box<");
self.push_type_name(inner_type, output);
output.push('>');
},
ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
output.push('*');
match mutbl {
hir::MutImmutable => output.push_str("const "),
hir::MutMutable => output.push_str("mut "),
}
if abi != ::abi::Abi::Rust {
output.push_str("extern \"");
output.push_str(abi.name());
output.push_str("\" ");
}
self.push_type_name(inner_type, output);
},
ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => {
output.push('&');
if mutbl == hir::MutMutable {
output.push_str("mut ");
}
output.push_str("fn(");
self.push_type_name(inner_type, output);
},
ty::TyArray(inner_type, len) => {
output.push('[');
self.push_type_name(inner_type, output);
write!(output, "; {}", len).unwrap();
output.push(']');
},
ty::TySlice(inner_type) => {
output.push('[');
self.push_type_name(inner_type, output);
output.push(']');
},
ty::TyTrait(ref trait_data) => {
self.push_def_path(trait_data.principal.def_id(), output);
self.push_type_params(trait_data.principal.skip_binder().substs,
&trait_data.projection_bounds,
output);
},
ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
if unsafety == hir::Unsafety::Unsafe {
output.push_str("unsafe ");
}
let sig = tcx.erase_late_bound_regions_and_normalize(sig);
if !sig.inputs.is_empty() {
for &parameter_type in &sig.inputs {
push_unique_type_name(tcx, parameter_type, output);
output.push_str(", ");
if abi != ::abi::Abi::Rust {
output.push_str("extern \"");
output.push_str(abi.name());
output.push_str("\" ");
}
output.pop();
output.pop();
}
if sig.variadic {
if !sig.inputs.is_empty() {
output.push_str(", ...");
} else {
output.push_str("...");
output.push_str("fn(");
let ty::FnSig {
inputs: sig_inputs,
output: sig_output,
variadic: sig_variadic
} = self.tcx.erase_late_bound_regions_and_normalize(sig);
if !sig_inputs.is_empty() {
for &parameter_type in &sig_inputs {
self.push_type_name(parameter_type, output);
output.push_str(", ");
}
output.pop();
output.pop();
}
if sig_variadic {
if !sig_inputs.is_empty() {
output.push_str(", ...");
} else {
output.push_str("...");
}
}
}
output.push(')');
output.push(')');
if !sig.output.is_nil() {
output.push_str(" -> ");
push_unique_type_name(tcx, sig.output, output);
if !sig_output.is_nil() {
output.push_str(" -> ");
self.push_type_name(sig_output, output);
}
},
ty::TyClosure(def_id, ref closure_substs) => {
self.push_def_path(def_id, output);
let generics = self.tcx.item_generics(self.tcx.closure_base_def_id(def_id));
let substs = closure_substs.substs.truncate_to(self.tcx, generics);
self.push_type_params(substs, &[], output);
}
ty::TyError |
ty::TyInfer(_) |
ty::TyProjection(..) |
ty::TyParam(_) |
ty::TyAnon(..) => {
bug!("DefPathBasedNames: Trying to create type name for \
unexpected type: {:?}", t);
}
},
ty::TyClosure(def_id, closure_substs) => {
push_item_name(tcx, def_id, output);
output.push_str("{");
output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize()));
output.push_str("}");
let generics = tcx.item_generics(tcx.closure_base_def_id(def_id));
let substs = closure_substs.substs.truncate_to(tcx, generics);
push_type_params(tcx, substs, &[], output);
}
ty::TyError |
ty::TyInfer(_) |
ty::TyProjection(..) |
ty::TyParam(_) |
ty::TyAnon(..) => {
bug!("debuginfo: Trying to create type name for \
unexpected type: {:?}", t);
}
}
}
fn push_item_name(tcx: TyCtxt,
def_id: DefId,
output: &mut String) {
let def_path = tcx.def_path(def_id);
// some_crate::
output.push_str(&tcx.crate_name(def_path.krate));
output.push_str("::");
pub fn push_def_path(&self,
def_id: DefId,
output: &mut String) {
let def_path = self.tcx.def_path(def_id);
// foo::bar::ItemName::
for part in tcx.def_path(def_id).data {
output.push_str(&format!("{}[{}]::",
part.data.as_interned_str(),
part.disambiguator));
}
// some_crate::
if !(self.omit_local_crate_name && def_id.is_local()) {
output.push_str(&self.tcx.crate_name(def_path.krate));
output.push_str("::");
}
// remove final "::"
output.pop();
output.pop();
}
// foo::bar::ItemName::
for part in self.tcx.def_path(def_id).data {
if self.omit_disambiguators {
write!(output, "{}::", part.data.as_interned_str()).unwrap();
} else {
write!(output, "{}[{}]::",
part.data.as_interned_str(),
part.disambiguator).unwrap();
}
}
fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
substs: &Substs<'tcx>,
projections: &[ty::PolyExistentialProjection<'tcx>],
output: &mut String) {
if substs.types().next().is_none() && projections.is_empty() {
return;
// remove final "::"
output.pop();
output.pop();
}
output.push('<');
for type_parameter in substs.types() {
push_unique_type_name(tcx, type_parameter, output);
output.push_str(", ");
}
pub fn push_type_params(&self,
substs: &Substs<'tcx>,
projections: &[ty::PolyExistentialProjection<'tcx>],
output: &mut String) {
if substs.types().next().is_none() && projections.is_empty() {
return;
}
for projection in projections {
let projection = projection.skip_binder();
let name = &projection.item_name.as_str();
output.push_str(name);
output.push_str("=");
push_unique_type_name(tcx, projection.ty, output);
output.push_str(", ");
}
output.push('<');
output.pop();
output.pop();
for type_parameter in substs.types() {
self.push_type_name(type_parameter, output);
output.push_str(", ");
}
output.push('>');
}
for projection in projections {
let projection = projection.skip_binder();
let name = &projection.item_name.as_str();
output.push_str(name);
output.push_str("=");
self.push_type_name(projection.ty, output);
output.push_str(", ");
}
fn push_instance_as_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
instance: Instance<'tcx>,
output: &mut String) {
push_item_name(tcx, instance.def, output);
push_type_params(tcx, instance.substs, &[], output);
}
output.pop();
output.pop();
pub fn def_id_to_string(tcx: TyCtxt, def_id: DefId) -> String {
let mut output = String::new();
push_item_name(tcx, def_id, &mut output);
output
}
output.push('>');
}
pub fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
ty: Ty<'tcx>)
-> String {
let mut output = String::new();
push_unique_type_name(tcx, ty, &mut output);
output
pub fn push_instance_as_string(&self,
instance: Instance<'tcx>,
output: &mut String) {
self.push_def_path(instance.def, output);
self.push_type_params(instance.substs, &[], output);
}
}
......@@ -10,14 +10,12 @@
#![allow(non_camel_case_types)]
use rustc::hir::def_id::DefId;
use abi::FnType;
use adt;
use common::*;
use machine;
use rustc::ty::{self, Ty, TypeFoldable};
use rustc::ty::subst::Substs;
use trans_item::DefPathBasedNames;
use type_::Type;
use syntax::ast;
......@@ -282,12 +280,12 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
let n = t.simd_size(cx.tcx()) as u64;
Type::vector(&llet, n)
}
ty::TyAdt(def, substs) => {
ty::TyAdt(..) => {
// Only create the named struct, but don't fill it in. We
// fill it in *after* placing it into the type cache. This
// avoids creating more than one copy of the enum when one
// of the enum's variants refers to the enum itself.
let name = llvm_type_name(cx, def.did, substs);
let name = llvm_type_name(cx, t);
adt::incomplete_type_of(cx, t, &name[..])
}
......@@ -319,21 +317,9 @@ pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>)
layout.align(&cx.tcx().data_layout).abi() as machine::llalign
}
fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
did: DefId,
substs: &Substs<'tcx>)
-> String {
let base = cx.tcx().item_path_str(did);
let strings: Vec<String> = substs.types().map(|t| t.to_string()).collect();
let tstr = if strings.is_empty() {
base
} else {
format!("{}<{}>", base, strings.join(", "))
};
if did.is_local() {
tstr
} else {
format!("{}.{}", did.krate, tstr)
}
fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String {
let mut name = String::with_capacity(32);
let printer = DefPathBasedNames::new(cx.tcx(), true, true);
printer.push_type_name(ty, &mut name);
name
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册