From e954fc4385e92907916135244fd2fe0e47b24deb Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 4 Dec 2014 16:44:51 -0500 Subject: [PATCH 01/17] librustc: Traverse arbitrarily deep for nullable enum opt. --- src/librustc_trans/trans/adt.rs | 166 ++++++++++++-------------- src/librustc_trans/trans/common.rs | 1 + src/librustc_trans/trans/debuginfo.rs | 14 +-- 3 files changed, 84 insertions(+), 97 deletions(-) diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 0d2876bdf81ce..44b86dc03c062 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -43,14 +43,13 @@ #![allow(unsigned_negation)] -pub use self::PointerField::*; pub use self::Repr::*; use std::num::Int; use std::rc::Rc; use llvm::{ValueRef, True, IntEQ, IntNE}; -use back::abi; +use back::abi::FAT_PTR_ADDR; use middle::subst; use middle::subst::Subst; use trans::_match; @@ -71,7 +70,6 @@ use util::ppaux::ty_to_string; type Hint = attr::ReprAttr; - /// Representations. #[deriving(Eq, PartialEq, Show)] pub enum Repr<'tcx> { @@ -101,7 +99,7 @@ pub enum Repr<'tcx> { nullfields: Vec> }, /// Two cases distinguished by a nullable pointer: the case with discriminant - /// `nndiscr` is represented by the struct `nonnull`, where the `ptrfield`th + /// `nndiscr` is represented by the struct `nonnull`, where the `discrfield`th /// field is known to be nonnull due to its type; if that field is null, then /// it represents the other case, which is inhabited by at most one value /// (and all other fields are undefined/unused). @@ -112,7 +110,7 @@ pub enum Repr<'tcx> { StructWrappedNullablePointer { nonnull: Struct<'tcx>, nndiscr: Disr, - ptrfield: PointerField, + discrfield: DiscrField, nullfields: Vec>, } } @@ -230,18 +228,20 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let st = mk_struct(cx, cases[discr].tys[], false, t); match cases[discr].find_ptr(cx) { - Some(ThinPointer(_)) if st.fields.len() == 1 => { + Some(ref pf) if pf.len() == 1 && st.fields.len() == 1 => { return RawNullablePointer { nndiscr: discr as Disr, nnty: st.fields[0], nullfields: cases[1 - discr].tys.clone() }; } - Some(ptrfield) => { + Some(pf) => { + let mut discrfield = vec![0]; + discrfield.extend(pf.into_iter()); return StructWrappedNullablePointer { nndiscr: discr as Disr, nonnull: st, - ptrfield: ptrfield, + discrfield: discrfield, nullfields: cases[1 - discr].tys.clone() }; } @@ -335,49 +335,67 @@ struct Case<'tcx> { tys: Vec> } +/// This represents the (GEP) indices to follow to get to the discriminant field +pub type DiscrField = Vec; -#[deriving(Copy, Eq, PartialEq, Show)] -pub enum PointerField { - ThinPointer(uint), - FatPointer(uint) -} +fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Option { + match ty.sty { + // &T/&mut T/Box could either be a thin or fat pointer depending on T + ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) => match ty.sty { + // &[T] and &str are a pointer and length pair + ty::ty_vec(_, None) | ty::ty_str => Some(vec![FAT_PTR_ADDR]), -impl<'tcx> Case<'tcx> { - fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>) - -> bool { - mk_struct(cx, self.tys[], false, scapegoat).size == 0 - } + ty::ty_struct(..) if !ty::type_is_sized(tcx, ty) => Some(vec![FAT_PTR_ADDR]), - fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option { - for (i, &ty) in self.tys.iter().enumerate() { - match ty.sty { - // &T/&mut T/Box could either be a thin or fat pointer depending on T - ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) => match ty.sty { - // &[T] and &str are a pointer and length pair - ty::ty_vec(_, None) | ty::ty_str => return Some(FatPointer(i)), + // Any other &T is just a pointer + _ => Some(vec![]) + }, - // &Trait is a pair of pointers: the actual object and a vtable - ty::ty_trait(..) => return Some(FatPointer(i)), + // Functions are just pointers + ty::ty_bare_fn(..) => Some(vec![]), - ty::ty_struct(..) if !ty::type_is_sized(cx.tcx(), ty) => { - return Some(FatPointer(i)) - } + // Closures are a pair of pointers: the code and environment + ty::ty_closure(..) => Some(vec![FAT_PTR_ADDR]), - // Any other &T is just a pointer - _ => return Some(ThinPointer(i)) - }, + // Perhaps one of the fields of this struct is non-null + // let's recurse and find out + ty::ty_struct(def_id, ref substs) => { + let fields = ty::lookup_struct_fields(tcx, def_id); + for (j, field) in fields.iter().enumerate() { + let field_ty = ty::lookup_field_type(tcx, def_id, field.id, substs); + match find_discr_field_candidate(tcx, field_ty) { + Some(v) => { + let mut discrfield = vec![j]; + discrfield.extend(v.into_iter()); + return Some(discrfield); + } + None => continue + } + } + None + }, - // Functions are just pointers - ty::ty_bare_fn(..) => return Some(ThinPointer(i)), + // Anything else is not a pointer + _ => None + } +} - // Closures are a pair of pointers: the code and environment - ty::ty_closure(..) => return Some(FatPointer(i)), +impl<'tcx> Case<'tcx> { + fn is_zerolen<'a>(&self, cx: &CrateContext<'a, 'tcx>, scapegoat: Ty<'tcx>) -> bool { + mk_struct(cx, self.tys[], false, scapegoat).size == 0 + } - // Anything else is not a pointer - _ => continue + fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option { + for (i, &ty) in self.tys.iter().enumerate() { + match find_discr_field_candidate(cx.tcx(), ty) { + Some(v) => { + let mut discrfield = vec![i]; + discrfield.extend(v.into_iter()); + return Some(discrfield); + } + None => continue } } - None } } @@ -709,8 +727,8 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, val = ICmp(bcx, cmp, Load(bcx, scrutinee), C_null(llptrty)); signed = false; } - StructWrappedNullablePointer { nndiscr, ptrfield, .. } => { - val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, ptrfield, scrutinee); + StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { + val = struct_wrapped_nullable_bitdiscr(bcx, nndiscr, discrfield, scrutinee); signed = false; } } @@ -720,12 +738,9 @@ pub fn trans_get_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, } } -fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, ptrfield: PointerField, +fn struct_wrapped_nullable_bitdiscr(bcx: Block, nndiscr: Disr, discrfield: &DiscrField, scrutinee: ValueRef) -> ValueRef { - let llptrptr = match ptrfield { - ThinPointer(field) => GEPi(bcx, scrutinee, &[0, field]), - FatPointer(field) => GEPi(bcx, scrutinee, &[0, field, abi::FAT_PTR_ADDR]) - }; + let llptrptr = GEPi(bcx, scrutinee, discrfield[]); let llptr = Load(bcx, llptrptr); let cmp = if nndiscr == 0 { IntEQ } else { IntNE }; ICmp(bcx, cmp, llptr, C_null(val_ty(llptr))) @@ -811,17 +826,10 @@ pub fn trans_set_discr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, Store(bcx, C_null(llptrty), val) } } - StructWrappedNullablePointer { ref nonnull, nndiscr, ptrfield, .. } => { + StructWrappedNullablePointer { nndiscr, ref discrfield, .. } => { if discr != nndiscr { - let (llptrptr, llptrty) = match ptrfield { - ThinPointer(field) => - (GEPi(bcx, val, &[0, field]), - type_of::type_of(bcx.ccx(), nonnull.fields[field])), - FatPointer(field) => { - let v = GEPi(bcx, val, &[0, field, abi::FAT_PTR_ADDR]); - (v, val_ty(v).element_type()) - } - }; + let llptrptr = GEPi(bcx, val, discrfield[]); + let llptrty = val_ty(llptrptr).element_type(); Store(bcx, C_null(llptrty), llptrptr) } } @@ -1041,7 +1049,7 @@ pub fn trans_const<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, r: &Repr<'tcx>, discr false) } else { let vals = nonnull.fields.iter().map(|&ty| { - // Always use null even if it's not the `ptrfield`th + // Always use null even if it's not the `discrfield`th // field; see #8506. C_null(type_of::sizing_type_of(ccx, ty)) }).collect::>(); @@ -1121,9 +1129,8 @@ fn padding(ccx: &CrateContext, size: u64) -> ValueRef { #[inline] fn roundup(x: u64, a: u32) -> u64 { let a = a as u64; ((x + (a - 1)) / a) * a } -/// Get the discriminant of a constant value. (Not currently used.) -pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) - -> Disr { +/// Get the discriminant of a constant value. +pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) -> Disr { match *r { CEnum(ity, _, _) => { match ity { @@ -1138,25 +1145,8 @@ pub fn const_get_discrim(ccx: &CrateContext, r: &Repr, val: ValueRef) } } Univariant(..) => 0, - RawNullablePointer { nndiscr, .. } => { - if is_null(val) { - /* subtraction as uint is ok because nndiscr is either 0 or 1 */ - (1 - nndiscr) as Disr - } else { - nndiscr - } - } - StructWrappedNullablePointer { nndiscr, ptrfield, .. } => { - let (idx, sub_idx) = match ptrfield { - ThinPointer(field) => (field, None), - FatPointer(field) => (field, Some(abi::FAT_PTR_ADDR)) - }; - if is_null(const_struct_field(ccx, val, idx, sub_idx)) { - /* subtraction as uint is ok because nndiscr is either 0 or 1 */ - (1 - nndiscr) as Disr - } else { - nndiscr - } + RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => { + ccx.sess().bug("const discrim access of non c-like enum") } } } @@ -1170,29 +1160,25 @@ pub fn const_get_field(ccx: &CrateContext, r: &Repr, val: ValueRef, _discr: Disr, ix: uint) -> ValueRef { match *r { CEnum(..) => ccx.sess().bug("element access in C-like enum const"), - Univariant(..) => const_struct_field(ccx, val, ix, None), - General(..) => const_struct_field(ccx, val, ix + 1, None), + Univariant(..) => const_struct_field(ccx, val, ix), + General(..) => const_struct_field(ccx, val, ix + 1), RawNullablePointer { .. } => { assert_eq!(ix, 0); val - } - StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix, None) + }, + StructWrappedNullablePointer{ .. } => const_struct_field(ccx, val, ix) } } /// Extract field of struct-like const, skipping our alignment padding. -fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint, sub_idx: Option) - -> ValueRef { +fn const_struct_field(ccx: &CrateContext, val: ValueRef, ix: uint) -> ValueRef { // Get the ix-th non-undef element of the struct. let mut real_ix = 0; // actual position in the struct let mut ix = ix; // logical index relative to real_ix let mut field; loop { loop { - field = match sub_idx { - Some(si) => const_get_elt(ccx, val, &[real_ix, si as u32]), - None => const_get_elt(ccx, val, &[real_ix]) - }; + field = const_get_elt(ccx, val, &[real_ix]); if !is_undef(field) { break; } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index ea2a4ef6b2801..d080cda4b819a 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -750,6 +750,7 @@ pub fn is_undef(val: ValueRef) -> bool { } } +#[allow(dead_code)] // potentially useful pub fn is_null(val: ValueRef) -> bool { unsafe { llvm::LLVMIsNull(val) != False diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 640e83469b269..b8c4a23b87acc 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -2292,14 +2292,14 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { }, adt::StructWrappedNullablePointer { nonnull: ref struct_def, nndiscr, - ptrfield, ..} => { + ref discrfield, ..} => { // Create a description of the non-null variant let (variant_type_metadata, variant_llvm_type, member_description_factory) = describe_enum_variant(cx, self.enum_type, struct_def, &*(*self.variants)[nndiscr as uint], - OptimizedDiscriminant(ptrfield), + OptimizedDiscriminant, self.containing_scope, self.span); @@ -2315,10 +2315,10 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { // member's name. let null_variant_index = (1 - nndiscr) as uint; let null_variant_name = token::get_name((*self.variants)[null_variant_index].name); - let discrfield = match ptrfield { - adt::ThinPointer(field) => format!("{}", field), - adt::FatPointer(field) => format!("{}", field) - }; + let discrfield = discrfield.iter() + .skip(1) + .map(|x| x.to_string()) + .collect::>().connect("$"); let union_member_name = format!("RUST$ENCODED$ENUM${}${}", discrfield, null_variant_name); @@ -2367,7 +2367,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> { #[deriving(Copy)] enum EnumDiscriminantInfo { RegularDiscriminant(DIType), - OptimizedDiscriminant(adt::PointerField), + OptimizedDiscriminant, NoDiscriminant } From e6b6234e66539a3e80aa48281ea1b72464eb90df Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 4 Dec 2014 16:55:56 -0500 Subject: [PATCH 02/17] librustc: Try looking in tuple fields for nullable enum opt. --- src/librustc_trans/trans/adt.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 44b86dc03c062..120e894b05025 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -375,6 +375,21 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Optio None }, + // Can we use one of the fields in this tuple? + ty::ty_tup(ref tys) => { + for (j, &ty) in tys.iter().enumerate() { + match find_discr_field_candidate(tcx, ty) { + Some(v) => { + let mut discrfield = vec![j]; + discrfield.extend(v.into_iter()); + return Some(discrfield); + } + None => continue + } + } + None + }, + // Anything else is not a pointer _ => None } From 5fb1e6b1e2952b1205baaa3fc9facaf7f5b34483 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 4 Dec 2014 16:56:26 -0500 Subject: [PATCH 03/17] librustc: Try looking in fixed sized arrays for nullable enum opt. --- src/librustc_trans/trans/adt.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 120e894b05025..28a2174889c13 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -390,6 +390,19 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Optio None }, + // Is this a fixed-size array of something non-zero + // with at least one element? + ty::ty_vec(ety, Some(d)) if d > 0 => { + match find_discr_field_candidate(tcx, ety) { + Some(v) => { + let mut discrfield = vec![0]; + discrfield.extend(v.into_iter()); + return Some(discrfield); + } + None => None + } + }, + // Anything else is not a pointer _ => None } From 6d91419f27b25810f2cfcd263e0e20b62910f4ff Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Fri, 5 Dec 2014 14:41:28 -0500 Subject: [PATCH 04/17] Add tests. --- src/test/run-pass/enum-null-pointer-opt.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index 2d4819231fad0..afed658a27b01 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -34,9 +34,21 @@ fn main() { // Pointers - Box assert_eq!(size_of::>(), size_of::>>()); - // The optimization can't apply to raw pointers assert!(size_of::>() != size_of::<*const int>()); assert!(Some(0 as *const int).is_some()); // Can't collapse None to null + struct Foo { + _a: Box + } + struct Bar(Box); + + // Should apply through structs + assert_eq!(size_of::(), size_of::>()); + assert_eq!(size_of::(), size_of::>()); + // and tuples + assert_eq!(size_of::<(u8, Box)>(), size_of::)>>()); + // and fixed-size arrays + assert_eq!(size_of::<[Box, ..1]>(), size_of::, ..1]>>()); + } From 46e73764896316ef1384591656cfca01280c5e5c Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 4 Dec 2014 16:56:57 -0500 Subject: [PATCH 05/17] librustc: Add NonZero lang item and use it if possible for nullable pointer enum opt. --- src/librustc/middle/lang_items.rs | 2 ++ src/librustc_trans/trans/adt.rs | 14 +++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index ca3087f08c410..90e3e2bb34aba 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -327,6 +327,8 @@ lets_do_this! { NoSyncItem, "no_sync_bound", no_sync_bound; ManagedItem, "managed_bound", managed_bound; + NonZeroItem, "non_zero", non_zero; + IteratorItem, "iterator", iterator; StackExhaustedLangItem, "stack_exhausted", stack_exhausted; diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 28a2174889c13..c3db50e3b20ae 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -357,7 +357,19 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Optio // Closures are a pair of pointers: the code and environment ty::ty_closure(..) => Some(vec![FAT_PTR_ADDR]), - // Perhaps one of the fields of this struct is non-null + // Is this the NonZero lang item wrapping a pointer or integer type? + ty::ty_struct(did, ref substs) if Some(did) == tcx.lang_items.non_zero() => { + let nonzero_fields = ty::lookup_struct_fields(tcx, did); + assert_eq!(nonzero_fields.len(), 1); + let nonzero_field = ty::lookup_field_type(tcx, did, nonzero_fields[0].id, substs); + match nonzero_field.sty { + ty::ty_ptr(..) | ty::ty_int(..) | + ty::ty_uint(..) => Some(vec![0]), + _ => None + } + }, + + // Perhaps one of the fields of this struct is non-zero // let's recurse and find out ty::ty_struct(def_id, ref substs) => { let fields = ty::lookup_struct_fields(tcx, def_id); From ef5da14edb09d6425b1b6576d418e12c268ddf17 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Wed, 3 Dec 2014 17:21:51 -0500 Subject: [PATCH 06/17] libcore: Add NonZero lang item and implement some methods. --- src/libcore/ptr.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 8c9d77a0e9cd7..910204edf70ab 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -90,6 +90,7 @@ use mem; use clone::Clone; use intrinsics; +use kinds::Copy; use option::Option; use option::Option::{Some, None}; use kinds::{Send, Sync}; @@ -109,6 +110,15 @@ pub use intrinsics::copy_memory; #[experimental = "uncertain about naming and semantics"] pub use intrinsics::set_memory; + +/// A wrapper type for raw pointers and integers that will never be +/// NULL or 0 that might allow certain optimizations. +#[lang="non_zero"] +#[deriving(Clone, PartialEq, Eq, PartialOrd)] +pub struct NonZero(pub T); + +impl Copy for NonZero {} + /// Creates a null raw pointer. /// /// # Examples @@ -313,6 +323,32 @@ impl RawPtr for *const T { } } +impl RawPtr for NonZero<*const T> { + #[inline] + fn null() -> NonZero<*const T> { NonZero(null()) } + + #[inline] + fn is_null(&self) -> bool { false } + + #[inline] + fn to_uint(&self) -> uint { + let NonZero(p) = *self; + p as uint + } + + #[inline] + unsafe fn offset(self, count: int) -> NonZero<*const T> { + let NonZero(p) = self; + NonZero(intrinsics::offset(p, count)) + } + + #[inline] + unsafe fn as_ref<'a>(&self) -> Option<&'a T> { + let NonZero(p) = *self; + Some(&*p) + } +} + impl RawPtr for *mut T { #[inline] fn null() -> *mut T { null_mut() } @@ -338,6 +374,32 @@ impl RawPtr for *mut T { } } +impl RawPtr for NonZero<*mut T> { + #[inline] + fn null() -> NonZero<*mut T> { NonZero(null_mut()) } + + #[inline] + fn is_null(&self) -> bool { false } + + #[inline] + fn to_uint(&self) -> uint { + let NonZero(p) = *self; + p as uint + } + + #[inline] + unsafe fn offset(self, count: int) -> NonZero<*mut T> { + let NonZero(p) = self; + NonZero(intrinsics::offset(p as *const T, count) as *mut T) + } + + #[inline] + unsafe fn as_ref<'a>(&self) -> Option<&'a T> { + let NonZero(p) = *self; + Some(&*p) + } +} + impl RawMutPtr for *mut T { #[inline] unsafe fn as_mut<'a>(&self) -> Option<&'a mut T> { @@ -349,6 +411,14 @@ impl RawMutPtr for *mut T { } } +impl RawMutPtr for NonZero<*mut T> { + #[inline] + unsafe fn as_mut<'a>(&self) -> Option<&'a mut T> { + let NonZero(p) = *self; + Some(&mut *p) + } +} + // Equality for pointers impl PartialEq for *const T { #[inline] From bb4473774866a1a9a3965a62db3298f1be874418 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Wed, 3 Dec 2014 17:22:11 -0500 Subject: [PATCH 07/17] libcollections: Use NonZero in Vec. --- src/libcollections/vec.rs | 57 ++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index d700b187e8a6d..0739cef335336 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -58,7 +58,7 @@ use core::kinds::marker::{ContravariantLifetime, InvariantType}; use core::mem; use core::num::{Int, UnsignedInt}; use core::ops; -use core::ptr::{mod, Unique}; +use core::ptr::{mod, NonZero}; use core::raw::Slice as RawSlice; use core::uint; @@ -133,7 +133,7 @@ use slice::CloneSliceExt; #[unsafe_no_drop_flag] #[stable] pub struct Vec { - ptr: Unique, + ptr: NonZero<*mut T>, len: uint, cap: uint, } @@ -176,7 +176,7 @@ impl Vec { // non-null value which is fine since we never call deallocate on the ptr // if cap is 0. The reason for this is because the pointer of a slice // being NULL would break the null pointer optimization for enums. - Vec { ptr: Unique(EMPTY as *mut T), len: 0, cap: 0 } + Vec { ptr: NonZero(EMPTY as *mut T), len: 0, cap: 0 } } /// Constructs a new, empty `Vec` with the specified capacity. @@ -209,7 +209,7 @@ impl Vec { #[stable] pub fn with_capacity(capacity: uint) -> Vec { if mem::size_of::() == 0 { - Vec { ptr: Unique(EMPTY as *mut T), len: 0, cap: uint::MAX } + Vec { ptr: NonZero(EMPTY as *mut T), len: 0, cap: uint::MAX } } else if capacity == 0 { Vec::new() } else { @@ -217,7 +217,7 @@ impl Vec { .expect("capacity overflow"); let ptr = unsafe { allocate(size, mem::min_align_of::()) }; if ptr.is_null() { ::alloc::oom() } - Vec { ptr: Unique(ptr as *mut T), len: 0, cap: capacity } + Vec { ptr: NonZero(ptr as *mut T), len: 0, cap: capacity } } } @@ -284,7 +284,7 @@ impl Vec { #[unstable = "needs finalization"] pub unsafe fn from_raw_parts(ptr: *mut T, length: uint, capacity: uint) -> Vec { - Vec { ptr: Unique(ptr), len: length, cap: capacity } + Vec { ptr: NonZero(ptr), len: length, cap: capacity } } /// Creates a vector by copying the elements from a raw pointer. @@ -792,10 +792,11 @@ impl Vec { pub fn shrink_to_fit(&mut self) { if mem::size_of::() == 0 { return } + let NonZero(ptr) = self.ptr; if self.len == 0 { if self.cap != 0 { unsafe { - dealloc(self.ptr.0, self.cap) + dealloc(ptr, self.cap) } self.cap = 0; } @@ -803,11 +804,12 @@ impl Vec { unsafe { // Overflow check is unnecessary as the vector is already at // least this large. - self.ptr = Unique(reallocate(self.ptr.0 as *mut u8, - self.cap * mem::size_of::(), - self.len * mem::size_of::(), - mem::min_align_of::()) as *mut T); - if self.ptr.0.is_null() { ::alloc::oom() } + let ptr = reallocate(ptr as *mut u8, + self.cap * mem::size_of::(), + self.len * mem::size_of::(), + mem::min_align_of::()) as *mut T; + if ptr.is_null() { ::alloc::oom() } + self.ptr = NonZero(ptr); } self.cap = self.len; } @@ -865,9 +867,10 @@ impl Vec { #[inline] #[stable] pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { + let NonZero(ptr) = self.ptr; unsafe { mem::transmute(RawSlice { - data: self.ptr.0 as *const T, + data: ptr as *const T, len: self.len, }) } @@ -890,9 +893,9 @@ impl Vec { #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn into_iter(self) -> IntoIter { unsafe { - let ptr = self.ptr.0; + let NonZero(ptr) = self.ptr; let cap = self.cap; - let begin = self.ptr.0 as *const T; + let begin = ptr as *const T; let end = if mem::size_of::() == 0 { (ptr as uint + self.len()) as *const T } else { @@ -1110,14 +1113,16 @@ impl Vec { let size = max(old_size, 2 * mem::size_of::()) * 2; if old_size > size { panic!("capacity overflow") } unsafe { - self.ptr = Unique(alloc_or_realloc(self.ptr.0, old_size, size)); - if self.ptr.0.is_null() { ::alloc::oom() } + let NonZero(ptr) = self.ptr; + let ptr = alloc_or_realloc(ptr, old_size, size); + if ptr.is_null() { ::alloc::oom() } + self.ptr = NonZero(ptr); } self.cap = max(self.cap, 2) * 2; } unsafe { - let end = self.ptr.0.offset(self.len as int); + let NonZero(end) = self.ptr.offset(self.len as int); ptr::write(&mut *end, value); self.len += 1; } @@ -1231,10 +1236,10 @@ impl Vec { let size = capacity.checked_mul(mem::size_of::()) .expect("capacity overflow"); unsafe { - self.ptr = Unique(alloc_or_realloc(self.ptr.0, - self.cap * mem::size_of::(), - size)); - if self.ptr.0.is_null() { ::alloc::oom() } + let NonZero(ptr) = self.ptr; + let ptr = alloc_or_realloc(ptr, self.cap * mem::size_of::(), size); + if ptr.is_null() { ::alloc::oom() } + self.ptr = NonZero(ptr); } self.cap = capacity; } @@ -1355,9 +1360,10 @@ impl AsSlice for Vec { #[inline] #[stable] fn as_slice<'a>(&'a self) -> &'a [T] { + let NonZero(ptr) = self.ptr; unsafe { mem::transmute(RawSlice { - data: self.ptr.0 as *const T, + data: ptr as *const T, len: self.len }) } @@ -1382,7 +1388,8 @@ impl Drop for Vec { for x in self.iter() { ptr::read(x); } - dealloc(self.ptr.0, self.cap) + let NonZero(ptr) = self.ptr; + dealloc(ptr, self.cap) } } } @@ -1420,7 +1427,7 @@ impl IntoIter { for _x in self { } let IntoIter { allocation, cap, ptr: _ptr, end: _end } = self; mem::forget(self); - Vec { ptr: Unique(allocation), cap: cap, len: 0 } + Vec { ptr: NonZero(allocation), cap: cap, len: 0 } } } From 0d48f76224371e884496182f6cfb3e2dad7690a2 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 4 Dec 2014 12:59:28 -0500 Subject: [PATCH 08/17] liballoc: Use NonZero in Rc. --- src/liballoc/rc.rs | 44 +++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index dfa55848c90da..41efa0468acbe 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -153,8 +153,7 @@ use core::mem::{transmute, min_align_of, size_of, forget}; use core::ops::{Deref, Drop}; use core::option::Option; use core::option::Option::{Some, None}; -use core::ptr; -use core::ptr::RawPtr; +use core::ptr::{mod, NonZero, RawPtr}; use core::result::Result; use core::result::Result::{Ok, Err}; @@ -174,7 +173,7 @@ struct RcBox { pub struct Rc { // FIXME #12808: strange names to try to avoid interfering with field accesses of the contained // type via Deref - _ptr: *mut RcBox, + _ptr: NonZero<*mut RcBox>, _nosend: marker::NoSend, _noshare: marker::NoSync } @@ -196,11 +195,11 @@ impl Rc { // there is an implicit weak pointer owned by all the strong pointers, which // ensures that the weak destructor never frees the allocation while the strong // destructor is running, even if the weak pointer is stored inside the strong one. - _ptr: transmute(box RcBox { + _ptr: NonZero(transmute(box RcBox { value: value, strong: Cell::new(1), weak: Cell::new(1) - }), + })), _nosend: marker::NoSend, _noshare: marker::NoSync } @@ -281,7 +280,8 @@ pub fn try_unwrap(rc: Rc) -> Result> { let val = ptr::read(&*rc); // copy the contained object // destruct the box and skip our Drop // we can ignore the refcounts because we know we're unique - deallocate(rc._ptr as *mut u8, size_of::>(), + let NonZero(ptr) = rc._ptr; + deallocate(ptr as *mut u8, size_of::>(), min_align_of::>()); forget(rc); Ok(val) @@ -311,7 +311,10 @@ pub fn try_unwrap(rc: Rc) -> Result> { #[experimental] pub fn get_mut<'a, T>(rc: &'a mut Rc) -> Option<&'a mut T> { if is_unique(rc) { - let inner = unsafe { &mut *rc._ptr }; + let inner = unsafe { + let NonZero(ptr) = rc._ptr; + &mut *ptr + }; Some(&mut inner.value) } else { None @@ -343,7 +346,10 @@ impl Rc { // pointer that will ever be returned to T. Our reference count is guaranteed to be 1 at // this point, and we required the `Rc` itself to be `mut`, so we're returning the only // possible reference to the inner value. - let inner = unsafe { &mut *self._ptr }; + let inner = unsafe { + let NonZero(ptr) = self._ptr; + &mut *ptr + }; &mut inner.value } } @@ -391,7 +397,8 @@ impl Drop for Rc { /// ``` fn drop(&mut self) { unsafe { - if !self._ptr.is_null() { + let NonZero(ptr) = self._ptr; + if !ptr.is_null() { self.dec_strong(); if self.strong() == 0 { ptr::read(&**self); // destroy the contained object @@ -401,7 +408,7 @@ impl Drop for Rc { self.dec_weak(); if self.weak() == 0 { - deallocate(self._ptr as *mut u8, size_of::>(), + deallocate(ptr as *mut u8, size_of::>(), min_align_of::>()) } } @@ -618,7 +625,7 @@ impl fmt::Show for Rc { pub struct Weak { // FIXME #12808: strange names to try to avoid interfering with // field accesses of the contained type via Deref - _ptr: *mut RcBox, + _ptr: NonZero<*mut RcBox>, _nosend: marker::NoSend, _noshare: marker::NoSync } @@ -682,12 +689,13 @@ impl Drop for Weak { /// ``` fn drop(&mut self) { unsafe { - if !self._ptr.is_null() { + let NonZero(ptr) = self._ptr; + if !ptr.is_null() { self.dec_weak(); // the weak count starts at 1, and will only go to zero if all the strong pointers // have disappeared. if self.weak() == 0 { - deallocate(self._ptr as *mut u8, size_of::>(), + deallocate(ptr as *mut u8, size_of::>(), min_align_of::>()) } } @@ -742,12 +750,18 @@ trait RcBoxPtr { impl RcBoxPtr for Rc { #[inline(always)] - fn inner(&self) -> &RcBox { unsafe { &(*self._ptr) } } + fn inner(&self) -> &RcBox { + let NonZero(ptr) = self._ptr; + unsafe { &(*ptr) } + } } impl RcBoxPtr for Weak { #[inline(always)] - fn inner(&self) -> &RcBox { unsafe { &(*self._ptr) } } + fn inner(&self) -> &RcBox { + let NonZero(ptr) = self._ptr; + unsafe { &(*ptr) } + } } #[cfg(test)] From 4af50548b9ed283acb62768624a8cd942eabe964 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 4 Dec 2014 13:29:47 -0500 Subject: [PATCH 09/17] liballoc: Use NonZero in Arc. --- src/liballoc/arc.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 8d8bbb429325b..290617535bb64 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -79,8 +79,7 @@ use core::mem; use core::ops::{Drop, Deref}; use core::option::Option; use core::option::Option::{Some, None}; -use core::ptr::RawPtr; -use core::ptr; +use core::ptr::{mod, NonZero, RawPtr}; use heap::deallocate; /// An atomically reference counted wrapper for shared state. @@ -114,7 +113,7 @@ use heap::deallocate; pub struct Arc { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref - _ptr: *mut ArcInner, + _ptr: NonZero<*mut ArcInner>, } unsafe impl Send for Arc { } @@ -130,7 +129,7 @@ unsafe impl Sync for Arc { } pub struct Weak { // FIXME #12808: strange name to try to avoid interfering with // field accesses of the contained type via Deref - _ptr: *mut ArcInner, + _ptr: NonZero<*mut ArcInner>, } unsafe impl Send for Weak { } @@ -165,7 +164,7 @@ impl Arc { weak: atomic::AtomicUint::new(1), data: data, }; - Arc { _ptr: unsafe { mem::transmute(x) } } + Arc { _ptr: NonZero(unsafe { mem::transmute(x) }) } } /// Downgrades the `Arc` to a `Weak` reference. @@ -194,7 +193,8 @@ impl Arc { // pointer is valid. Furthermore, we know that the `ArcInner` structure itself is `Sync` // because the inner data is `Sync` as well, so we're ok loaning out an immutable pointer // to these contents. - unsafe { &*self._ptr } + let NonZero(ptr) = self._ptr; + unsafe { &*ptr } } } @@ -281,7 +281,8 @@ impl Arc { // pointer that will ever be returned to T. Our reference count is guaranteed to be 1 at // this point, and we required the Arc itself to be `mut`, so we're returning the only // possible reference to the inner data. - let inner = unsafe { &mut *self._ptr }; + let NonZero(ptr) = self._ptr; + let inner = unsafe { &mut *ptr }; &mut inner.data } } @@ -316,7 +317,8 @@ impl Drop for Arc { fn drop(&mut self) { // This structure has #[unsafe_no_drop_flag], so this drop glue may run more than once (but // it is guaranteed to be zeroed after the first if it's run more than once) - if self._ptr.is_null() { return } + let NonZero(ptr) = self._ptr; + if ptr.is_null() { return } // Because `fetch_sub` is already atomic, we do not need to synchronize with other threads // unless we are going to delete the object. This same logic applies to the below @@ -346,7 +348,7 @@ impl Drop for Arc { if self.inner().weak.fetch_sub(1, atomic::Release) == 1 { atomic::fence(atomic::Acquire); - unsafe { deallocate(self._ptr as *mut u8, size_of::>(), + unsafe { deallocate(ptr as *mut u8, size_of::>(), min_align_of::>()) } } } @@ -386,7 +388,8 @@ impl Weak { #[inline] fn inner(&self) -> &ArcInner { // See comments above for why this is "safe" - unsafe { &*self._ptr } + let NonZero(ptr) = self._ptr; + unsafe { &*ptr } } } @@ -442,14 +445,16 @@ impl Drop for Weak { /// } // implicit drop /// ``` fn drop(&mut self) { + let NonZero(ptr) = self._ptr; + // see comments above for why this check is here - if self._ptr.is_null() { return } + if ptr.is_null() { return } // If we find out that we were the last weak pointer, then its time to deallocate the data // entirely. See the discussion in Arc::drop() about the memory orderings if self.inner().weak.fetch_sub(1, atomic::Release) == 1 { atomic::fence(atomic::Acquire); - unsafe { deallocate(self._ptr as *mut u8, size_of::>(), + unsafe { deallocate(ptr as *mut u8, size_of::>(), min_align_of::>()) } } } From 466135bfef4d110213a9aeb46f8199fa89a5f267 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 4 Dec 2014 14:58:21 -0500 Subject: [PATCH 10/17] libcore: Make it unsafe to create NonZero and impl Deref. --- src/liballoc/arc.rs | 15 +++++-------- src/liballoc/rc.rs | 29 +++++++----------------- src/libcollections/vec.rs | 46 +++++++++++++++++---------------------- src/libcore/ptr.rs | 24 +++++++++++++++++--- 4 files changed, 55 insertions(+), 59 deletions(-) diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 290617535bb64..47e7ddac07ce2 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -164,7 +164,7 @@ impl Arc { weak: atomic::AtomicUint::new(1), data: data, }; - Arc { _ptr: NonZero(unsafe { mem::transmute(x) }) } + Arc { _ptr: unsafe { NonZero::new(mem::transmute(x)) } } } /// Downgrades the `Arc` to a `Weak` reference. @@ -193,8 +193,7 @@ impl Arc { // pointer is valid. Furthermore, we know that the `ArcInner` structure itself is `Sync` // because the inner data is `Sync` as well, so we're ok loaning out an immutable pointer // to these contents. - let NonZero(ptr) = self._ptr; - unsafe { &*ptr } + unsafe { &**self._ptr } } } @@ -281,8 +280,7 @@ impl Arc { // pointer that will ever be returned to T. Our reference count is guaranteed to be 1 at // this point, and we required the Arc itself to be `mut`, so we're returning the only // possible reference to the inner data. - let NonZero(ptr) = self._ptr; - let inner = unsafe { &mut *ptr }; + let inner = unsafe { &mut **self._ptr }; &mut inner.data } } @@ -317,7 +315,7 @@ impl Drop for Arc { fn drop(&mut self) { // This structure has #[unsafe_no_drop_flag], so this drop glue may run more than once (but // it is guaranteed to be zeroed after the first if it's run more than once) - let NonZero(ptr) = self._ptr; + let ptr = *self._ptr; if ptr.is_null() { return } // Because `fetch_sub` is already atomic, we do not need to synchronize with other threads @@ -388,8 +386,7 @@ impl Weak { #[inline] fn inner(&self) -> &ArcInner { // See comments above for why this is "safe" - let NonZero(ptr) = self._ptr; - unsafe { &*ptr } + unsafe { &**self._ptr } } } @@ -445,7 +442,7 @@ impl Drop for Weak { /// } // implicit drop /// ``` fn drop(&mut self) { - let NonZero(ptr) = self._ptr; + let ptr = *self._ptr; // see comments above for why this check is here if ptr.is_null() { return } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 41efa0468acbe..3d73c64bf4d64 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -195,7 +195,7 @@ impl Rc { // there is an implicit weak pointer owned by all the strong pointers, which // ensures that the weak destructor never frees the allocation while the strong // destructor is running, even if the weak pointer is stored inside the strong one. - _ptr: NonZero(transmute(box RcBox { + _ptr: NonZero::new(transmute(box RcBox { value: value, strong: Cell::new(1), weak: Cell::new(1) @@ -280,8 +280,7 @@ pub fn try_unwrap(rc: Rc) -> Result> { let val = ptr::read(&*rc); // copy the contained object // destruct the box and skip our Drop // we can ignore the refcounts because we know we're unique - let NonZero(ptr) = rc._ptr; - deallocate(ptr as *mut u8, size_of::>(), + deallocate(*rc._ptr as *mut u8, size_of::>(), min_align_of::>()); forget(rc); Ok(val) @@ -311,10 +310,7 @@ pub fn try_unwrap(rc: Rc) -> Result> { #[experimental] pub fn get_mut<'a, T>(rc: &'a mut Rc) -> Option<&'a mut T> { if is_unique(rc) { - let inner = unsafe { - let NonZero(ptr) = rc._ptr; - &mut *ptr - }; + let inner = unsafe { &mut **rc._ptr }; Some(&mut inner.value) } else { None @@ -346,10 +342,7 @@ impl Rc { // pointer that will ever be returned to T. Our reference count is guaranteed to be 1 at // this point, and we required the `Rc` itself to be `mut`, so we're returning the only // possible reference to the inner value. - let inner = unsafe { - let NonZero(ptr) = self._ptr; - &mut *ptr - }; + let inner = unsafe { &mut **self._ptr }; &mut inner.value } } @@ -397,7 +390,7 @@ impl Drop for Rc { /// ``` fn drop(&mut self) { unsafe { - let NonZero(ptr) = self._ptr; + let ptr = *self._ptr; if !ptr.is_null() { self.dec_strong(); if self.strong() == 0 { @@ -689,7 +682,7 @@ impl Drop for Weak { /// ``` fn drop(&mut self) { unsafe { - let NonZero(ptr) = self._ptr; + let ptr = *self._ptr; if !ptr.is_null() { self.dec_weak(); // the weak count starts at 1, and will only go to zero if all the strong pointers @@ -750,18 +743,12 @@ trait RcBoxPtr { impl RcBoxPtr for Rc { #[inline(always)] - fn inner(&self) -> &RcBox { - let NonZero(ptr) = self._ptr; - unsafe { &(*ptr) } - } + fn inner(&self) -> &RcBox { unsafe { &(**self._ptr) } } } impl RcBoxPtr for Weak { #[inline(always)] - fn inner(&self) -> &RcBox { - let NonZero(ptr) = self._ptr; - unsafe { &(*ptr) } - } + fn inner(&self) -> &RcBox { unsafe { &(**self._ptr) } } } #[cfg(test)] diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 0739cef335336..6f61865728041 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -176,7 +176,7 @@ impl Vec { // non-null value which is fine since we never call deallocate on the ptr // if cap is 0. The reason for this is because the pointer of a slice // being NULL would break the null pointer optimization for enums. - Vec { ptr: NonZero(EMPTY as *mut T), len: 0, cap: 0 } + Vec { ptr: unsafe { NonZero::new(EMPTY as *mut T) }, len: 0, cap: 0 } } /// Constructs a new, empty `Vec` with the specified capacity. @@ -209,7 +209,7 @@ impl Vec { #[stable] pub fn with_capacity(capacity: uint) -> Vec { if mem::size_of::() == 0 { - Vec { ptr: NonZero(EMPTY as *mut T), len: 0, cap: uint::MAX } + Vec { ptr: unsafe { NonZero::new(EMPTY as *mut T) }, len: 0, cap: uint::MAX } } else if capacity == 0 { Vec::new() } else { @@ -217,7 +217,7 @@ impl Vec { .expect("capacity overflow"); let ptr = unsafe { allocate(size, mem::min_align_of::()) }; if ptr.is_null() { ::alloc::oom() } - Vec { ptr: NonZero(ptr as *mut T), len: 0, cap: capacity } + Vec { ptr: unsafe { NonZero::new(ptr as *mut T) }, len: 0, cap: capacity } } } @@ -284,7 +284,7 @@ impl Vec { #[unstable = "needs finalization"] pub unsafe fn from_raw_parts(ptr: *mut T, length: uint, capacity: uint) -> Vec { - Vec { ptr: NonZero(ptr), len: length, cap: capacity } + Vec { ptr: NonZero::new(ptr), len: length, cap: capacity } } /// Creates a vector by copying the elements from a raw pointer. @@ -792,11 +792,10 @@ impl Vec { pub fn shrink_to_fit(&mut self) { if mem::size_of::() == 0 { return } - let NonZero(ptr) = self.ptr; if self.len == 0 { if self.cap != 0 { unsafe { - dealloc(ptr, self.cap) + dealloc(*self.ptr, self.cap) } self.cap = 0; } @@ -804,12 +803,12 @@ impl Vec { unsafe { // Overflow check is unnecessary as the vector is already at // least this large. - let ptr = reallocate(ptr as *mut u8, + let ptr = reallocate(*self.ptr as *mut u8, self.cap * mem::size_of::(), self.len * mem::size_of::(), mem::min_align_of::()) as *mut T; if ptr.is_null() { ::alloc::oom() } - self.ptr = NonZero(ptr); + self.ptr = NonZero::new(ptr); } self.cap = self.len; } @@ -867,10 +866,9 @@ impl Vec { #[inline] #[stable] pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { - let NonZero(ptr) = self.ptr; unsafe { mem::transmute(RawSlice { - data: ptr as *const T, + data: *self.ptr as *const T, len: self.len, }) } @@ -893,7 +891,7 @@ impl Vec { #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn into_iter(self) -> IntoIter { unsafe { - let NonZero(ptr) = self.ptr; + let ptr = *self.ptr; let cap = self.cap; let begin = ptr as *const T; let end = if mem::size_of::() == 0 { @@ -1113,16 +1111,15 @@ impl Vec { let size = max(old_size, 2 * mem::size_of::()) * 2; if old_size > size { panic!("capacity overflow") } unsafe { - let NonZero(ptr) = self.ptr; - let ptr = alloc_or_realloc(ptr, old_size, size); + let ptr = alloc_or_realloc(*self.ptr, old_size, size); if ptr.is_null() { ::alloc::oom() } - self.ptr = NonZero(ptr); + self.ptr = NonZero::new(ptr); } self.cap = max(self.cap, 2) * 2; } unsafe { - let NonZero(end) = self.ptr.offset(self.len as int); + let end = *self.ptr.offset(self.len as int); ptr::write(&mut *end, value); self.len += 1; } @@ -1167,11 +1164,11 @@ impl Vec { #[unstable = "matches collection reform specification, waiting for dust to settle"] pub fn drain<'a>(&'a mut self) -> Drain<'a, T> { unsafe { - let begin = self.ptr.0 as *const T; + let begin = *self.ptr as *const T; let end = if mem::size_of::() == 0 { - (self.ptr.0 as uint + self.len()) as *const T + (*self.ptr as uint + self.len()) as *const T } else { - self.ptr.0.offset(self.len() as int) as *const T + (*self.ptr).offset(self.len() as int) as *const T }; self.set_len(0); Drain { @@ -1236,10 +1233,9 @@ impl Vec { let size = capacity.checked_mul(mem::size_of::()) .expect("capacity overflow"); unsafe { - let NonZero(ptr) = self.ptr; - let ptr = alloc_or_realloc(ptr, self.cap * mem::size_of::(), size); + let ptr = alloc_or_realloc(*self.ptr, self.cap * mem::size_of::(), size); if ptr.is_null() { ::alloc::oom() } - self.ptr = NonZero(ptr); + self.ptr = NonZero::new(ptr); } self.cap = capacity; } @@ -1360,10 +1356,9 @@ impl AsSlice for Vec { #[inline] #[stable] fn as_slice<'a>(&'a self) -> &'a [T] { - let NonZero(ptr) = self.ptr; unsafe { mem::transmute(RawSlice { - data: ptr as *const T, + data: *self.ptr as *const T, len: self.len }) } @@ -1388,8 +1383,7 @@ impl Drop for Vec { for x in self.iter() { ptr::read(x); } - let NonZero(ptr) = self.ptr; - dealloc(ptr, self.cap) + dealloc(*self.ptr, self.cap) } } } @@ -1427,7 +1421,7 @@ impl IntoIter { for _x in self { } let IntoIter { allocation, cap, ptr: _ptr, end: _end } = self; mem::forget(self); - Vec { ptr: NonZero(allocation), cap: cap, len: 0 } + Vec { ptr: NonZero::new(allocation), cap: cap, len: 0 } } } diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 910204edf70ab..23eb117680a02 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -90,10 +90,10 @@ use mem; use clone::Clone; use intrinsics; -use kinds::Copy; +use kinds::{Copy, Send, Sync}; +use ops::Deref; use option::Option; use option::Option::{Some, None}; -use kinds::{Send, Sync}; use cmp::{PartialEq, Eq, Ord, PartialOrd, Equiv}; use cmp::Ordering; @@ -115,7 +115,25 @@ pub use intrinsics::set_memory; /// NULL or 0 that might allow certain optimizations. #[lang="non_zero"] #[deriving(Clone, PartialEq, Eq, PartialOrd)] -pub struct NonZero(pub T); +#[experimental] +pub struct NonZero(T); + +impl NonZero { + /// Create an instance of NonZero with the provided value. + /// You must indeed ensure that the value is actually "non-zero". + #[inline(always)] + pub unsafe fn new(inner: T) -> NonZero { + NonZero(inner) + } +} + +impl Deref for NonZero { + #[inline] + fn deref<'a>(&'a self) -> &'a T { + let NonZero(ref inner) = *self; + inner + } +} impl Copy for NonZero {} From e83272b62883f97b8717a8150d894e89d7ae18d6 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Fri, 5 Dec 2014 14:52:38 -0500 Subject: [PATCH 11/17] Add tests for NonZero. --- src/test/run-pass/enum-null-pointer-opt.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index afed658a27b01..f0e34f0dc4b1f 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -10,6 +10,9 @@ use std::mem::size_of; +use std::ptr::NonZero; +use std::rc::Rc; +use std::sync::Arc; trait Trait {} @@ -51,4 +54,16 @@ fn main() { // and fixed-size arrays assert_eq!(size_of::<[Box, ..1]>(), size_of::, ..1]>>()); + // Should apply to NonZero + assert_eq!(size_of::>(), size_of::>>()); + assert_eq!(size_of::>(), size_of::>>()); + + // Should apply to types that use NonZero internally + assert_eq!(size_of::>(), size_of::>>()); + assert_eq!(size_of::>(), size_of::>>()); + assert_eq!(size_of::>(), size_of::>>()); + + // Should apply to types that have NonZero transitively + assert_eq!(size_of::(), size_of::>()); + } From b44d7cb89c57b1fc0495b337dfddbe5cdc2ed6b2 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 11 Dec 2014 22:29:24 -0500 Subject: [PATCH 12/17] Don't expose NonZero through libstd. --- src/liballoc/arc.rs | 3 +- src/liballoc/rc.rs | 3 +- src/libcollections/vec.rs | 3 +- src/libcore/lib.rs | 1 + src/libcore/nonzero.rs | 98 ++++++++++++++++++++++ src/libcore/ptr.rs | 89 +------------------- src/test/run-pass/enum-null-pointer-opt.rs | 4 +- 7 files changed, 109 insertions(+), 92 deletions(-) create mode 100644 src/libcore/nonzero.rs diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 47e7ddac07ce2..3e235caab18ad 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -76,10 +76,11 @@ use core::default::Default; use core::kinds::{Sync, Send}; use core::mem::{min_align_of, size_of, drop}; use core::mem; +use core::nonzero::NonZero; use core::ops::{Drop, Deref}; use core::option::Option; use core::option::Option::{Some, None}; -use core::ptr::{mod, NonZero, RawPtr}; +use core::ptr::{mod, RawPtr}; use heap::deallocate; /// An atomically reference counted wrapper for shared state. diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 3d73c64bf4d64..13dc4474c1a19 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -150,10 +150,11 @@ use core::fmt; use core::hash::{mod, Hash}; use core::kinds::marker; use core::mem::{transmute, min_align_of, size_of, forget}; +use core::nonzero::NonZero; use core::ops::{Deref, Drop}; use core::option::Option; use core::option::Option::{Some, None}; -use core::ptr::{mod, NonZero, RawPtr}; +use core::ptr::{mod, RawPtr}; use core::result::Result; use core::result::Result::{Ok, Err}; diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index 6f61865728041..f65527d3f6664 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -56,9 +56,10 @@ use core::hash::{mod, Hash}; use core::iter::repeat; use core::kinds::marker::{ContravariantLifetime, InvariantType}; use core::mem; +use core::nonzero::NonZero; use core::num::{Int, UnsignedInt}; use core::ops; -use core::ptr::{mod, NonZero}; +use core::ptr; use core::raw::Slice as RawSlice; use core::uint; diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 6d0d6e0817abd..d646245510d50 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -93,6 +93,7 @@ pub mod prelude; pub mod intrinsics; pub mod mem; +pub mod nonzero; pub mod ptr; /* Core language traits */ diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs new file mode 100644 index 0000000000000..f976f08bf843c --- /dev/null +++ b/src/libcore/nonzero.rs @@ -0,0 +1,98 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Exposes the NonZero lang item which provides optimization hints. + +use cmp::Eq; +use intrinsics; +use kinds::Copy; +use ops::Deref; +use option::Option; +use option::Option::Some; +use ptr::{null, null_mut, RawPtr, RawMutPtr}; + +/// A wrapper type for raw pointers and integers that will never be +/// NULL or 0 that might allow certain optimizations. +#[lang="non_zero"] +#[deriving(Clone, PartialEq, Eq, PartialOrd)] +#[experimental] +pub struct NonZero(T); + +impl NonZero { + /// Create an instance of NonZero with the provided value. + /// You must indeed ensure that the value is actually "non-zero". + #[inline(always)] + pub unsafe fn new(inner: T) -> NonZero { + NonZero(inner) + } +} + +impl Copy for NonZero {} + +impl Deref for NonZero { + #[inline] + fn deref<'a>(&'a self) -> &'a T { + let NonZero(ref inner) = *self; + inner + } +} + +impl RawPtr for NonZero<*const T> { + #[inline] + fn null() -> NonZero<*const T> { NonZero(null()) } + + #[inline] + fn is_null(&self) -> bool { false } + + #[inline] + fn to_uint(&self) -> uint { + **self as uint + } + + #[inline] + unsafe fn offset(self, count: int) -> NonZero<*const T> { + NonZero(intrinsics::offset(*self, count)) + } + + #[inline] + unsafe fn as_ref<'a>(&self) -> Option<&'a T> { + Some(&***self) + } +} + +impl RawPtr for NonZero<*mut T> { + #[inline] + fn null() -> NonZero<*mut T> { NonZero(null_mut()) } + + #[inline] + fn is_null(&self) -> bool { false } + + #[inline] + fn to_uint(&self) -> uint { + **self as uint + } + + #[inline] + unsafe fn offset(self, count: int) -> NonZero<*mut T> { + NonZero(intrinsics::offset(*self as *const T, count) as *mut T) + } + + #[inline] + unsafe fn as_ref<'a>(&self) -> Option<&'a T> { + Some(&***self) + } +} + +impl RawMutPtr for NonZero<*mut T> { + #[inline] + unsafe fn as_mut<'a>(&self) -> Option<&'a mut T> { + Some(&mut ***self) + } +} diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 23eb117680a02..8c724b4d8521f 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -90,8 +90,7 @@ use mem; use clone::Clone; use intrinsics; -use kinds::{Copy, Send, Sync}; -use ops::Deref; +use kinds::{Send, Sync}; use option::Option; use option::Option::{Some, None}; @@ -111,32 +110,6 @@ pub use intrinsics::copy_memory; pub use intrinsics::set_memory; -/// A wrapper type for raw pointers and integers that will never be -/// NULL or 0 that might allow certain optimizations. -#[lang="non_zero"] -#[deriving(Clone, PartialEq, Eq, PartialOrd)] -#[experimental] -pub struct NonZero(T); - -impl NonZero { - /// Create an instance of NonZero with the provided value. - /// You must indeed ensure that the value is actually "non-zero". - #[inline(always)] - pub unsafe fn new(inner: T) -> NonZero { - NonZero(inner) - } -} - -impl Deref for NonZero { - #[inline] - fn deref<'a>(&'a self) -> &'a T { - let NonZero(ref inner) = *self; - inner - } -} - -impl Copy for NonZero {} - /// Creates a null raw pointer. /// /// # Examples @@ -341,32 +314,6 @@ impl RawPtr for *const T { } } -impl RawPtr for NonZero<*const T> { - #[inline] - fn null() -> NonZero<*const T> { NonZero(null()) } - - #[inline] - fn is_null(&self) -> bool { false } - - #[inline] - fn to_uint(&self) -> uint { - let NonZero(p) = *self; - p as uint - } - - #[inline] - unsafe fn offset(self, count: int) -> NonZero<*const T> { - let NonZero(p) = self; - NonZero(intrinsics::offset(p, count)) - } - - #[inline] - unsafe fn as_ref<'a>(&self) -> Option<&'a T> { - let NonZero(p) = *self; - Some(&*p) - } -} - impl RawPtr for *mut T { #[inline] fn null() -> *mut T { null_mut() } @@ -392,32 +339,6 @@ impl RawPtr for *mut T { } } -impl RawPtr for NonZero<*mut T> { - #[inline] - fn null() -> NonZero<*mut T> { NonZero(null_mut()) } - - #[inline] - fn is_null(&self) -> bool { false } - - #[inline] - fn to_uint(&self) -> uint { - let NonZero(p) = *self; - p as uint - } - - #[inline] - unsafe fn offset(self, count: int) -> NonZero<*mut T> { - let NonZero(p) = self; - NonZero(intrinsics::offset(p as *const T, count) as *mut T) - } - - #[inline] - unsafe fn as_ref<'a>(&self) -> Option<&'a T> { - let NonZero(p) = *self; - Some(&*p) - } -} - impl RawMutPtr for *mut T { #[inline] unsafe fn as_mut<'a>(&self) -> Option<&'a mut T> { @@ -429,14 +350,6 @@ impl RawMutPtr for *mut T { } } -impl RawMutPtr for NonZero<*mut T> { - #[inline] - unsafe fn as_mut<'a>(&self) -> Option<&'a mut T> { - let NonZero(p) = *self; - Some(&mut *p) - } -} - // Equality for pointers impl PartialEq for *const T { #[inline] diff --git a/src/test/run-pass/enum-null-pointer-opt.rs b/src/test/run-pass/enum-null-pointer-opt.rs index f0e34f0dc4b1f..d8d74c8bb45ae 100644 --- a/src/test/run-pass/enum-null-pointer-opt.rs +++ b/src/test/run-pass/enum-null-pointer-opt.rs @@ -9,8 +9,10 @@ // except according to those terms. +extern crate core; + +use core::nonzero::NonZero; use std::mem::size_of; -use std::ptr::NonZero; use std::rc::Rc; use std::sync::Arc; From c15df8e68f62a973b322109101ead205830dc767 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sun, 21 Dec 2014 21:40:20 -0500 Subject: [PATCH 13/17] libcore: Don't impl RawPtr* traits for NonZero. --- src/libcollections/vec.rs | 2 +- src/libcore/nonzero.rs | 63 +-------------------------------------- 2 files changed, 2 insertions(+), 63 deletions(-) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index f65527d3f6664..a45e1aa24163a 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -1120,7 +1120,7 @@ impl Vec { } unsafe { - let end = *self.ptr.offset(self.len as int); + let end = (*self.ptr).offset(self.len as int); ptr::write(&mut *end, value); self.len += 1; } diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index f976f08bf843c..43903871c3f7c 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -10,18 +10,12 @@ //! Exposes the NonZero lang item which provides optimization hints. -use cmp::Eq; -use intrinsics; -use kinds::Copy; use ops::Deref; -use option::Option; -use option::Option::Some; -use ptr::{null, null_mut, RawPtr, RawMutPtr}; /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. #[lang="non_zero"] -#[deriving(Clone, PartialEq, Eq, PartialOrd)] +#[deriving(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Show)] #[experimental] pub struct NonZero(T); @@ -34,8 +28,6 @@ impl NonZero { } } -impl Copy for NonZero {} - impl Deref for NonZero { #[inline] fn deref<'a>(&'a self) -> &'a T { @@ -43,56 +35,3 @@ impl Deref for NonZero { inner } } - -impl RawPtr for NonZero<*const T> { - #[inline] - fn null() -> NonZero<*const T> { NonZero(null()) } - - #[inline] - fn is_null(&self) -> bool { false } - - #[inline] - fn to_uint(&self) -> uint { - **self as uint - } - - #[inline] - unsafe fn offset(self, count: int) -> NonZero<*const T> { - NonZero(intrinsics::offset(*self, count)) - } - - #[inline] - unsafe fn as_ref<'a>(&self) -> Option<&'a T> { - Some(&***self) - } -} - -impl RawPtr for NonZero<*mut T> { - #[inline] - fn null() -> NonZero<*mut T> { NonZero(null_mut()) } - - #[inline] - fn is_null(&self) -> bool { false } - - #[inline] - fn to_uint(&self) -> uint { - **self as uint - } - - #[inline] - unsafe fn offset(self, count: int) -> NonZero<*mut T> { - NonZero(intrinsics::offset(*self as *const T, count) as *mut T) - } - - #[inline] - unsafe fn as_ref<'a>(&self) -> Option<&'a T> { - Some(&***self) - } -} - -impl RawMutPtr for NonZero<*mut T> { - #[inline] - unsafe fn as_mut<'a>(&self) -> Option<&'a mut T> { - Some(&mut ***self) - } -} From 27617a10f6647e98a90adbfce4f881c32c82a4dc Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sun, 21 Dec 2014 22:21:53 -0500 Subject: [PATCH 14/17] librustc_trans: Get rid of unnecessary allocation in finding discriminant field. --- src/librustc_trans/trans/adt.rs | 85 +++++++++++++++------------------ 1 file changed, 38 insertions(+), 47 deletions(-) diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index c3db50e3b20ae..cd788945d3b28 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -228,16 +228,16 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, let st = mk_struct(cx, cases[discr].tys[], false, t); match cases[discr].find_ptr(cx) { - Some(ref pf) if pf.len() == 1 && st.fields.len() == 1 => { + Some(ref df) if df.len() == 1 && st.fields.len() == 1 => { return RawNullablePointer { nndiscr: discr as Disr, nnty: st.fields[0], nullfields: cases[1 - discr].tys.clone() }; } - Some(pf) => { - let mut discrfield = vec![0]; - discrfield.extend(pf.into_iter()); + Some(mut discrfield) => { + discrfield.push(0); + discrfield.reverse(); return StructWrappedNullablePointer { nndiscr: discr as Disr, nonnull: st, @@ -245,7 +245,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, nullfields: cases[1 - discr].tys.clone() }; } - None => { } + None => {} } } discr += 1; @@ -338,24 +338,27 @@ struct Case<'tcx> { /// This represents the (GEP) indices to follow to get to the discriminant field pub type DiscrField = Vec; -fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Option { +fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, + ty: Ty<'tcx>, + mut path: DiscrField) -> Option { match ty.sty { - // &T/&mut T/Box could either be a thin or fat pointer depending on T - ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) => match ty.sty { - // &[T] and &str are a pointer and length pair - ty::ty_vec(_, None) | ty::ty_str => Some(vec![FAT_PTR_ADDR]), - - ty::ty_struct(..) if !ty::type_is_sized(tcx, ty) => Some(vec![FAT_PTR_ADDR]), - - // Any other &T is just a pointer - _ => Some(vec![]) + // Fat &T/&mut T/Box i.e. T is [T], str, or Trait + ty::ty_rptr(_, ty::mt { ty, .. }) | ty::ty_uniq(ty) if !ty::type_is_sized(tcx, ty) => { + path.push(FAT_PTR_ADDR); + Some(path) }, + // Regular thin pointer: &T/&mut T/Box + ty::ty_rptr(..) | ty::ty_uniq(..) => Some(path), + // Functions are just pointers - ty::ty_bare_fn(..) => Some(vec![]), + ty::ty_bare_fn(..) => Some(path), // Closures are a pair of pointers: the code and environment - ty::ty_closure(..) => Some(vec![FAT_PTR_ADDR]), + ty::ty_closure(..) => { + path.push(FAT_PTR_ADDR); + Some(path) + }, // Is this the NonZero lang item wrapping a pointer or integer type? ty::ty_struct(did, ref substs) if Some(did) == tcx.lang_items.non_zero() => { @@ -363,8 +366,10 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Optio assert_eq!(nonzero_fields.len(), 1); let nonzero_field = ty::lookup_field_type(tcx, did, nonzero_fields[0].id, substs); match nonzero_field.sty { - ty::ty_ptr(..) | ty::ty_int(..) | - ty::ty_uint(..) => Some(vec![0]), + ty::ty_ptr(..) | ty::ty_int(..) | ty::ty_uint(..) => { + path.push(0); + Some(path) + }, _ => None } }, @@ -375,13 +380,9 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Optio let fields = ty::lookup_struct_fields(tcx, def_id); for (j, field) in fields.iter().enumerate() { let field_ty = ty::lookup_field_type(tcx, def_id, field.id, substs); - match find_discr_field_candidate(tcx, field_ty) { - Some(v) => { - let mut discrfield = vec![j]; - discrfield.extend(v.into_iter()); - return Some(discrfield); - } - None => continue + if let Some(mut fpath) = find_discr_field_candidate(tcx, field_ty, path.clone()) { + fpath.push(j); + return Some(fpath); } } None @@ -390,13 +391,9 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Optio // Can we use one of the fields in this tuple? ty::ty_tup(ref tys) => { for (j, &ty) in tys.iter().enumerate() { - match find_discr_field_candidate(tcx, ty) { - Some(v) => { - let mut discrfield = vec![j]; - discrfield.extend(v.into_iter()); - return Some(discrfield); - } - None => continue + if let Some(mut fpath) = find_discr_field_candidate(tcx, ty, path.clone()) { + fpath.push(j); + return Some(fpath); } } None @@ -405,13 +402,11 @@ fn find_discr_field_candidate<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> Optio // Is this a fixed-size array of something non-zero // with at least one element? ty::ty_vec(ety, Some(d)) if d > 0 => { - match find_discr_field_candidate(tcx, ety) { - Some(v) => { - let mut discrfield = vec![0]; - discrfield.extend(v.into_iter()); - return Some(discrfield); - } - None => None + if let Some(mut vpath) = find_discr_field_candidate(tcx, ety, path) { + vpath.push(0); + Some(vpath) + } else { + None } }, @@ -427,13 +422,9 @@ impl<'tcx> Case<'tcx> { fn find_ptr<'a>(&self, cx: &CrateContext<'a, 'tcx>) -> Option { for (i, &ty) in self.tys.iter().enumerate() { - match find_discr_field_candidate(cx.tcx(), ty) { - Some(v) => { - let mut discrfield = vec![i]; - discrfield.extend(v.into_iter()); - return Some(discrfield); - } - None => continue + if let Some(mut path) = find_discr_field_candidate(cx.tcx(), ty, vec![]) { + path.push(i); + return Some(path); } } None From 94f12615735b833750b35eed7805d8a5a9898c1f Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sun, 21 Dec 2014 22:43:36 -0500 Subject: [PATCH 15/17] libcore: Use Zeroable trait to try to limit what types may be used with NonZero. --- src/libcore/nonzero.rs | 60 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 43903871c3f7c..131627329462e 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -12,14 +12,30 @@ use ops::Deref; +/// Unsafe trait to indicate what types are usable with the NonZero struct +pub unsafe trait Zeroable {} + +unsafe impl Zeroable for *const T {} +unsafe impl Zeroable for *mut T {} +unsafe impl Zeroable for int {} +unsafe impl Zeroable for uint {} +unsafe impl Zeroable for i8 {} +unsafe impl Zeroable for u8 {} +unsafe impl Zeroable for i16 {} +unsafe impl Zeroable for u16 {} +unsafe impl Zeroable for i32 {} +unsafe impl Zeroable for u32 {} +unsafe impl Zeroable for i64 {} +unsafe impl Zeroable for u64 {} + /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. #[lang="non_zero"] #[deriving(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Show)] #[experimental] -pub struct NonZero(T); +pub struct NonZero(T); -impl NonZero { +impl NonZero { /// Create an instance of NonZero with the provided value. /// You must indeed ensure that the value is actually "non-zero". #[inline(always)] @@ -28,10 +44,48 @@ impl NonZero { } } -impl Deref for NonZero { +impl Deref for NonZero { #[inline] fn deref<'a>(&'a self) -> &'a T { let NonZero(ref inner) = *self; inner } } + +#[cfg(test)] +mod test { + use super::NonZero; + + #[test] + fn test_create_nonzero_instance() { + let _a = unsafe { + NonZero::new(21) + }; + } + + #[test] + fn test_size_nonzero_in_option() { + use mem::size_of; + use option::Option; + + assert_eq!(size_of::>(), size_of::>>()); + } + + #[test] + fn test_match_on_nonzero_option() { + use option::Some; + + let a = Some(unsafe { + NonZero::new(42) + }); + match a { + Some(val) => assert_eq!(*val, 42), + None => panic!("unexpected None while matching on Some(NonZero(_))") + } + + match unsafe { NonZero::new(43) } { + Some(val) => assert_eq!(*val, 43), + None => panic!("unexpected None while matching on Some(NonZero(_))") + } + } +} From 0e039ada55bab9b94ceb3fabff409790e37635c6 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Tue, 23 Dec 2014 15:52:02 -0500 Subject: [PATCH 16/17] libcoretest: Add tests for NonZero. --- src/libcore/nonzero.rs | 38 -------------- src/libcoretest/lib.rs | 1 + src/libcoretest/nonzero.rs | 100 +++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 38 deletions(-) create mode 100644 src/libcoretest/nonzero.rs diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 131627329462e..c429e4b8212bc 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -51,41 +51,3 @@ impl Deref for NonZero { inner } } - -#[cfg(test)] -mod test { - use super::NonZero; - - #[test] - fn test_create_nonzero_instance() { - let _a = unsafe { - NonZero::new(21) - }; - } - - #[test] - fn test_size_nonzero_in_option() { - use mem::size_of; - use option::Option; - - assert_eq!(size_of::>(), size_of::>>()); - } - - #[test] - fn test_match_on_nonzero_option() { - use option::Some; - - let a = Some(unsafe { - NonZero::new(42) - }); - match a { - Some(val) => assert_eq!(*val, 42), - None => panic!("unexpected None while matching on Some(NonZero(_))") - } - - match unsafe { NonZero::new(43) } { - Some(val) => assert_eq!(*val, 43), - None => panic!("unexpected None while matching on Some(NonZero(_))") - } - } -} diff --git a/src/libcoretest/lib.rs b/src/libcoretest/lib.rs index 44029ebb7fa0f..e6608eee3ddfa 100644 --- a/src/libcoretest/lib.rs +++ b/src/libcoretest/lib.rs @@ -25,6 +25,7 @@ mod fmt; mod hash; mod iter; mod mem; +mod nonzero; mod num; mod ops; mod option; diff --git a/src/libcoretest/nonzero.rs b/src/libcoretest/nonzero.rs new file mode 100644 index 0000000000000..ed66be3d890dc --- /dev/null +++ b/src/libcoretest/nonzero.rs @@ -0,0 +1,100 @@ +// Copyright 2012-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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::nonzero::NonZero; +use core::option::Option; +use core::option::Option::{Some, None}; +use std::mem::size_of; + +#[test] +fn test_create_nonzero_instance() { + let _a = unsafe { + NonZero::new(21i) + }; +} + +#[test] +fn test_size_nonzero_in_option() { + assert_eq!(size_of::>(), size_of::>>()); +} + +#[test] +fn test_match_on_nonzero_option() { + let a = Some(unsafe { + NonZero::new(42i) + }); + match a { + Some(val) => assert_eq!(*val, 42), + None => panic!("unexpected None while matching on Some(NonZero(_))") + } + + match unsafe { Some(NonZero::new(43i)) } { + Some(val) => assert_eq!(*val, 43), + None => panic!("unexpected None while matching on Some(NonZero(_))") + } +} + +#[test] +fn test_match_option_empty_vec() { + let a: Option> = Some(vec![]); + match a { + None => panic!("unexpected None while matching on Some(vec![])"), + _ => {} + } +} + +#[test] +fn test_match_option_vec() { + let a = Some(vec![1i, 2, 3, 4]); + match a { + Some(v) => assert_eq!(v, vec![1i, 2, 3, 4]), + None => panic!("unexpected None while matching on Some(vec![1, 2, 3, 4])") + } +} + +#[test] +fn test_match_option_rc() { + use std::rc::Rc; + + let five = Rc::new(5i); + match Some(five) { + Some(r) => assert_eq!(*r, 5i), + None => panic!("unexpected None while matching on Some(Rc::new(5))") + } +} + +#[test] +fn test_match_option_arc() { + use std::sync::Arc; + + let five = Arc::new(5i); + match Some(five) { + Some(a) => assert_eq!(*a, 5i), + None => panic!("unexpected None while matching on Some(Arc::new(5))") + } +} + +#[test] +fn test_match_option_empty_string() { + let a = Some(String::new()); + match a { + None => panic!("unexpected None while matching on Some(String::new())"), + _ => {} + } +} + +#[test] +fn test_match_option_string() { + let five = "Five".into_string(); + match Some(five) { + Some(s) => assert_eq!(s, "Five"), + None => panic!("unexpected None while matching on Some(String { ... })") + } +} From 766a71922fcabb8e0885b372d116c07149b6bb07 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Sun, 28 Dec 2014 14:36:45 -0500 Subject: [PATCH 17/17] libcollections: impl Send/Sync for Vec. --- src/libcollections/vec.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs index a45e1aa24163a..bf69980b49c8f 100644 --- a/src/libcollections/vec.rs +++ b/src/libcollections/vec.rs @@ -139,6 +139,9 @@ pub struct Vec { cap: uint, } +unsafe impl Send for Vec { } +unsafe impl Sync for Vec { } + /// A clone-on-write vector pub type CowVec<'a, T> = Cow<'a, Vec, [T]>;