Merge branch 'master' of git://github.com/rust-lang/rust into rust

This commit is contained in:
Erick Rivas 2015-01-11 10:40:16 -06:00
commit 84813d3fbc
10 changed files with 76 additions and 15 deletions

View File

@ -302,6 +302,7 @@ impl String {
/// assert_eq!(String::from_utf16_lossy(v), /// assert_eq!(String::from_utf16_lossy(v),
/// "𝄞mus\u{FFFD}ic\u{FFFD}".to_string()); /// "𝄞mus\u{FFFD}ic\u{FFFD}".to_string());
/// ``` /// ```
#[inline]
#[stable] #[stable]
pub fn from_utf16_lossy(v: &[u16]) -> String { pub fn from_utf16_lossy(v: &[u16]) -> String {
unicode_str::utf16_items(v).map(|c| c.to_char_lossy()).collect() unicode_str::utf16_items(v).map(|c| c.to_char_lossy()).collect()
@ -556,6 +557,7 @@ impl String {
/// assert_eq!(s.remove(1), 'o'); /// assert_eq!(s.remove(1), 'o');
/// assert_eq!(s.remove(0), 'o'); /// assert_eq!(s.remove(0), 'o');
/// ``` /// ```
#[inline]
#[stable] #[stable]
pub fn remove(&mut self, idx: uint) -> char { pub fn remove(&mut self, idx: uint) -> char {
let len = self.len(); let len = self.len();
@ -582,6 +584,7 @@ impl String {
/// ///
/// If `idx` does not lie on a character boundary or is out of bounds, then /// If `idx` does not lie on a character boundary or is out of bounds, then
/// this function will panic. /// this function will panic.
#[inline]
#[stable] #[stable]
pub fn insert(&mut self, idx: uint, ch: char) { pub fn insert(&mut self, idx: uint, ch: char) {
let len = self.len(); let len = self.len();
@ -618,6 +621,7 @@ impl String {
/// } /// }
/// assert_eq!(s.as_slice(), "olleh"); /// assert_eq!(s.as_slice(), "olleh");
/// ``` /// ```
#[inline]
#[stable] #[stable]
pub unsafe fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec<u8> { pub unsafe fn as_mut_vec<'a>(&'a mut self) -> &'a mut Vec<u8> {
&mut self.vec &mut self.vec
@ -645,6 +649,7 @@ impl String {
/// v.push('a'); /// v.push('a');
/// assert!(!v.is_empty()); /// assert!(!v.is_empty());
/// ``` /// ```
#[inline]
#[stable] #[stable]
pub fn is_empty(&self) -> bool { self.len() == 0 } pub fn is_empty(&self) -> bool { self.len() == 0 }
@ -801,6 +806,7 @@ impl Str for String {
#[stable] #[stable]
impl Default for String { impl Default for String {
#[inline]
#[stable] #[stable]
fn default() -> String { fn default() -> String {
String::new() String::new()
@ -809,6 +815,7 @@ impl Default for String {
#[stable] #[stable]
impl fmt::String for String { impl fmt::String for String {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::String::fmt(&**self, f) fmt::String::fmt(&**self, f)
} }
@ -816,6 +823,7 @@ impl fmt::String for String {
#[unstable = "waiting on fmt stabilization"] #[unstable = "waiting on fmt stabilization"]
impl fmt::Show for String { impl fmt::Show for String {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Show::fmt(&**self, f) fmt::Show::fmt(&**self, f)
} }
@ -842,6 +850,7 @@ impl<H: hash::Writer + hash::Hasher> hash::Hash<H> for String {
impl<'a> Add<&'a str> for String { impl<'a> Add<&'a str> for String {
type Output = String; type Output = String;
#[inline]
fn add(mut self, other: &str) -> String { fn add(mut self, other: &str) -> String {
self.push_str(other); self.push_str(other);
self self
@ -881,6 +890,7 @@ impl ops::Index<ops::FullRange> for String {
impl ops::Deref for String { impl ops::Deref for String {
type Target = str; type Target = str;
#[inline]
fn deref<'a>(&'a self) -> &'a str { fn deref<'a>(&'a self) -> &'a str {
unsafe { mem::transmute(&self.vec[]) } unsafe { mem::transmute(&self.vec[]) }
} }
@ -895,6 +905,7 @@ pub struct DerefString<'a> {
impl<'a> Deref for DerefString<'a> { impl<'a> Deref for DerefString<'a> {
type Target = String; type Target = String;
#[inline]
fn deref<'b>(&'b self) -> &'b String { fn deref<'b>(&'b self) -> &'b String {
unsafe { mem::transmute(&*self.x) } unsafe { mem::transmute(&*self.x) }
} }
@ -933,6 +944,7 @@ pub trait ToString {
} }
impl<T: fmt::String + ?Sized> ToString for T { impl<T: fmt::String + ?Sized> ToString for T {
#[inline]
fn to_string(&self) -> String { fn to_string(&self) -> String {
use core::fmt::Writer; use core::fmt::Writer;
let mut buf = String::new(); let mut buf = String::new();
@ -943,12 +955,14 @@ impl<T: fmt::String + ?Sized> ToString for T {
} }
impl IntoCow<'static, String, str> for String { impl IntoCow<'static, String, str> for String {
#[inline]
fn into_cow(self) -> CowString<'static> { fn into_cow(self) -> CowString<'static> {
Cow::Owned(self) Cow::Owned(self)
} }
} }
impl<'a> IntoCow<'a, String, str> for &'a str { impl<'a> IntoCow<'a, String, str> for &'a str {
#[inline]
fn into_cow(self) -> CowString<'a> { fn into_cow(self) -> CowString<'a> {
Cow::Borrowed(self) Cow::Borrowed(self)
} }
@ -966,6 +980,7 @@ impl<'a> Str for CowString<'a> {
} }
impl fmt::Writer for String { impl fmt::Writer for String {
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result { fn write_str(&mut self, s: &str) -> fmt::Result {
self.push_str(s); self.push_str(s);
Ok(()) Ok(())

View File

@ -1054,6 +1054,11 @@ pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
C_undef(type_of::type_of(cx.ccx(), t)) C_undef(type_of::type_of(cx.ccx(), t))
} else if ty::type_is_bool(t) { } else if ty::type_is_bool(t) {
Trunc(cx, LoadRangeAssert(cx, ptr, 0, 2, llvm::False), Type::i1(cx.ccx())) Trunc(cx, LoadRangeAssert(cx, ptr, 0, 2, llvm::False), Type::i1(cx.ccx()))
} else if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
// We want to pass small aggregates as immediate values, but using an aggregate LLVM type
// for this leads to bad optimizations, so its arg type is an appropriately sized integer
// and we have to convert it
Load(cx, BitCast(cx, ptr, type_of::arg_type_of(cx.ccx(), t).ptr_to()))
} else if ty::type_is_char(t) { } else if ty::type_is_char(t) {
// a char is a Unicode codepoint, and so takes values from 0 // a char is a Unicode codepoint, and so takes values from 0
// to 0x10FFFF inclusive only. // to 0x10FFFF inclusive only.
@ -1065,9 +1070,14 @@ pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
/// Helper for storing values in memory. Does the necessary conversion if the in-memory type /// Helper for storing values in memory. Does the necessary conversion if the in-memory type
/// differs from the type used for SSA values. /// differs from the type used for SSA values.
pub fn store_ty(cx: Block, v: ValueRef, dst: ValueRef, t: Ty) { pub fn store_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, dst: ValueRef, t: Ty<'tcx>) {
if ty::type_is_bool(t) { if ty::type_is_bool(t) {
Store(cx, ZExt(cx, v, Type::i8(cx.ccx())), dst); Store(cx, ZExt(cx, v, Type::i8(cx.ccx())), dst);
} else if type_is_immediate(cx.ccx(), t) && type_of::type_of(cx.ccx(), t).is_aggregate() {
// We want to pass small aggregates as immediate values, but using an aggregate LLVM type
// for this leads to bad optimizations, so its arg type is an appropriately sized integer
// and we have to convert it
Store(cx, v, BitCast(cx, dst, type_of::arg_type_of(cx.ccx(), t).ptr_to()));
} else { } else {
Store(cx, v, dst); Store(cx, v, dst);
}; };

View File

@ -222,10 +222,7 @@ fn type_is_newtype_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
match ty.sty { match ty.sty {
ty::ty_struct(def_id, substs) => { ty::ty_struct(def_id, substs) => {
let fields = ty::struct_fields(ccx.tcx(), def_id, substs); let fields = ty::struct_fields(ccx.tcx(), def_id, substs);
fields.len() == 1 && fields.len() == 1 && type_is_immediate(ccx, fields[0].mt.ty)
fields[0].name ==
token::special_idents::unnamed_field.name &&
type_is_immediate(ccx, fields[0].mt.ty)
} }
_ => false _ => false
} }
@ -247,7 +244,7 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
return false; return false;
} }
match ty.sty { match ty.sty {
ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) | ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) | ty::ty_vec(_, Some(_)) |
ty::ty_unboxed_closure(..) => { ty::ty_unboxed_closure(..) => {
let llty = sizing_type_of(ccx, ty); let llty = sizing_type_of(ccx, ty);
llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type()) llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type())

View File

@ -736,6 +736,13 @@ pub fn trans_rust_fn_with_foreign_abi<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
if ty::type_is_bool(rust_ty) { if ty::type_is_bool(rust_ty) {
let tmp = builder.load_range_assert(llforeign_arg, 0, 2, llvm::False); let tmp = builder.load_range_assert(llforeign_arg, 0, 2, llvm::False);
builder.trunc(tmp, Type::i1(ccx)) builder.trunc(tmp, Type::i1(ccx))
} else if type_of::type_of(ccx, rust_ty).is_aggregate() {
// We want to pass small aggregates as immediate values, but using an aggregate
// LLVM type for this leads to bad optimizations, so its arg type is an
// appropriately sized integer and we have to convert it
let tmp = builder.bitcast(llforeign_arg,
type_of::arg_type_of(ccx, rust_ty).ptr_to());
builder.load(tmp)
} else { } else {
builder.load(llforeign_arg) builder.load(llforeign_arg)
} }
@ -834,10 +841,10 @@ fn foreign_signature<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
fn_sig: &ty::FnSig<'tcx>, fn_sig: &ty::FnSig<'tcx>,
arg_tys: &[Ty<'tcx>]) arg_tys: &[Ty<'tcx>])
-> LlvmSignature { -> LlvmSignature {
let llarg_tys = arg_tys.iter().map(|&arg| arg_type_of(ccx, arg)).collect(); let llarg_tys = arg_tys.iter().map(|&arg| foreign_arg_type_of(ccx, arg)).collect();
let (llret_ty, ret_def) = match fn_sig.output { let (llret_ty, ret_def) = match fn_sig.output {
ty::FnConverging(ret_ty) => ty::FnConverging(ret_ty) =>
(type_of::arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)), (type_of::foreign_arg_type_of(ccx, ret_ty), !return_type_is_void(ccx, ret_ty)),
ty::FnDiverging => ty::FnDiverging =>
(Type::nil(ccx), false) (Type::nil(ccx), false)
}; };

View File

@ -138,7 +138,7 @@ pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
-> Block<'blk, 'tcx> { -> Block<'blk, 'tcx> {
let _icx = push_ctxt("drop_ty_immediate"); let _icx = push_ctxt("drop_ty_immediate");
let vp = alloca(bcx, type_of(bcx.ccx(), t), ""); let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
Store(bcx, v, vp); store_ty(bcx, v, vp, t);
drop_ty(bcx, vp, t, source_location) drop_ty(bcx, vp, t, source_location)
} }

View File

@ -357,11 +357,11 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
&ccx.link_meta().crate_hash); &ccx.link_meta().crate_hash);
// NB: This needs to be kept in lockstep with the TypeId struct in // NB: This needs to be kept in lockstep with the TypeId struct in
// the intrinsic module // the intrinsic module
C_named_struct(llret_ty, &[C_u64(ccx, hash)]) C_u64(ccx, hash)
} }
(_, "init") => { (_, "init") => {
let tp_ty = *substs.types.get(FnSpace, 0); let tp_ty = *substs.types.get(FnSpace, 0);
let lltp_ty = type_of::type_of(ccx, tp_ty); let lltp_ty = type_of::arg_type_of(ccx, tp_ty);
if return_type_is_void(ccx, tp_ty) { if return_type_is_void(ccx, tp_ty) {
C_nil(ccx) C_nil(ccx)
} else { } else {
@ -686,6 +686,11 @@ fn with_overflow_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, name: &'static st
let ret = C_undef(type_of::type_of(bcx.ccx(), t)); let ret = C_undef(type_of::type_of(bcx.ccx(), t));
let ret = InsertValue(bcx, ret, result, 0); let ret = InsertValue(bcx, ret, result, 0);
let ret = InsertValue(bcx, ret, overflow, 1); let ret = InsertValue(bcx, ret, overflow, 1);
if type_is_immediate(bcx.ccx(), t) {
ret let tmp = alloc_ty(bcx, t, "tmp");
Store(bcx, ret, tmp);
load_ty(bcx, tmp, t)
} else {
ret
}
} }

View File

@ -82,6 +82,11 @@ impl Type {
ty!(llvm::LLVMInt64TypeInContext(ccx.llcx())) ty!(llvm::LLVMInt64TypeInContext(ccx.llcx()))
} }
// Creates an integer type with the given number of bits, e.g. i24
pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type {
ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint))
}
pub fn f32(ccx: &CrateContext) -> Type { pub fn f32(ccx: &CrateContext) -> Type {
ty!(llvm::LLVMFloatTypeInContext(ccx.llcx())) ty!(llvm::LLVMFloatTypeInContext(ccx.llcx()))
} }
@ -260,6 +265,13 @@ impl Type {
ty!(llvm::LLVMPointerType(self.to_ref(), 0)) ty!(llvm::LLVMPointerType(self.to_ref(), 0))
} }
pub fn is_aggregate(&self) -> bool {
match self.kind() {
TypeKind::Struct | TypeKind::Array => true,
_ => false
}
}
pub fn is_packed(&self) -> bool { pub fn is_packed(&self) -> bool {
unsafe { unsafe {
llvm::LLVMIsPackedStruct(self.to_ref()) == True llvm::LLVMIsPackedStruct(self.to_ref()) == True

View File

@ -243,9 +243,24 @@ pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Typ
llsizingty llsizingty
} }
pub fn foreign_arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
if ty::type_is_bool(t) {
Type::i1(cx)
} else {
type_of(cx, t)
}
}
pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
if ty::type_is_bool(t) { if ty::type_is_bool(t) {
Type::i1(cx) Type::i1(cx)
} else if type_is_immediate(cx, t) && type_of(cx, t).is_aggregate() {
// We want to pass small aggregates as immediate values, but using an aggregate LLVM type
// for this leads to bad optimizations, so its arg type is an appropriately sized integer
match machine::llsize_of_alloc(cx, sizing_type_of(cx, t)) {
0 => type_of(cx, t),
n => Type::ix(cx, n * 8),
}
} else { } else {
type_of(cx, t) type_of(cx, t)
} }

View File

@ -19,5 +19,5 @@ fn f() {
} }
pub fn main() { pub fn main() {
let _t = Thread::spawn(f); let _t = Thread::scoped(f);
} }

View File

@ -15,7 +15,7 @@ extern crate "weak-lang-items" as other;
use std::thread::Thread; use std::thread::Thread;
fn main() { fn main() {
let _ = Thread::spawn(move|| { let _ = Thread::scoped(move|| {
other::foo() other::foo()
}); });
} }