From 843db01bd925279da0a56efde532c9e3ecf73610 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 15 Apr 2015 11:57:29 +1200 Subject: eddyb's changes for DST coercions + lots of rebasing --- src/liballoc/rc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/liballoc/rc.rs') diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 015d0330ed7..a1b5e6e6baf 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -173,9 +173,9 @@ use core::intrinsics::assume; use heap::deallocate; struct RcBox { - value: T, strong: Cell, - weak: Cell + weak: Cell, + value: T } /// A reference-counted pointer type over an immutable value. -- cgit 1.4.1-3-g733a5 From 7d953538d10c4a31300afd27f73563adb056beab Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 16 Apr 2015 14:36:47 +1200 Subject: Make Rc DST-compatible --- src/liballoc/rc.rs | 389 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 382 insertions(+), 7 deletions(-) (limited to 'src/liballoc/rc.rs') diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index a1b5e6e6baf..4e8a7e8bfc9 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -159,7 +159,7 @@ use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering}; use core::default::Default; use core::fmt; use core::hash::{Hasher, Hash}; -use core::marker; +use core::marker::{self, Sized}; use core::mem::{self, min_align_of, size_of, forget}; use core::nonzero::NonZero; use core::ops::{Deref, Drop}; @@ -170,17 +170,36 @@ use core::result::Result; use core::result::Result::{Ok, Err}; use core::intrinsics::assume; +#[cfg(not(stage0))] +use core::intrinsics::drop_in_place; +#[cfg(not(stage0))] +use core::marker::Unsize; +#[cfg(not(stage0))] +use core::mem::{min_align_of_val, size_of_val}; +#[cfg(not(stage0))] +use core::ops::CoerceUnsized; + use heap::deallocate; +#[cfg(stage0)] struct RcBox { strong: Cell, weak: Cell, - value: T + value: T, +} + +#[cfg(not(stage0))] +struct RcBox { + strong: Cell, + weak: Cell, + value: T, } + /// A reference-counted pointer type over an immutable value. /// /// See the [module level documentation](./index.html) for more details. +#[cfg(stage0)] #[unsafe_no_drop_flag] #[stable(feature = "rust1", since = "1.0.0")] pub struct Rc { @@ -188,11 +207,30 @@ pub struct Rc { // accesses of the contained type via Deref _ptr: NonZero<*mut RcBox>, } +#[cfg(not(stage0))] +#[unsafe_no_drop_flag] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Rc { + // FIXME #12808: strange names to try to avoid interfering with field + // accesses of the contained type via Deref + _ptr: NonZero<*mut RcBox>, +} +#[cfg(stage0)] impl !marker::Send for Rc {} +#[cfg(not(stage0))] +impl !marker::Send for Rc {} + +#[cfg(stage0)] impl !marker::Sync for Rc {} +#[cfg(not(stage0))] +impl !marker::Sync for Rc {} + +#[cfg(not(stage0))] // SNAP c64d671 +impl, U: ?Sized> CoerceUnsized> for Rc {} + impl Rc { /// Constructs a new `Rc`. /// @@ -212,14 +250,39 @@ impl Rc { // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. _ptr: NonZero::new(boxed::into_raw(box RcBox { - value: value, strong: Cell::new(1), - weak: Cell::new(1) + weak: Cell::new(1), + value: value })), } } } +} +#[cfg(not(stage0))] +impl Rc { + /// Downgrades the `Rc` to a `Weak` reference. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let weak_five = five.downgrade(); + /// ``` + #[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module")] + pub fn downgrade(&self) -> Weak { + self.inc_weak(); + Weak { _ptr: self._ptr } + } +} + +#[cfg(stage0)] +impl Rc { /// Downgrades the `Rc` to a `Weak` reference. /// /// # Examples @@ -241,14 +304,24 @@ impl Rc { } /// Get the number of weak references to this value. +#[cfg(stage0)] #[inline] #[unstable(feature = "alloc")] pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } +#[cfg(not(stage0))] +#[inline] +#[unstable(feature = "alloc")] +pub fn weak_count(this: &Rc) -> usize { this.weak() - 1 } /// Get the number of strong references to this value. +#[cfg(stage0)] #[inline] #[unstable(feature = "alloc")] pub fn strong_count(this: &Rc) -> usize { this.strong() } +#[cfg(not(stage0))] +#[inline] +#[unstable(feature = "alloc")] +pub fn strong_count(this: &Rc) -> usize { this.strong() } /// Returns true if there are no other `Rc` or `Weak` values that share the /// same inner value. @@ -365,6 +438,7 @@ impl Rc { } } +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Rc { type Target = T; @@ -374,7 +448,19 @@ impl Deref for Rc { &self.inner().value } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Deref for Rc { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + &self.inner().value + } +} +#[cfg(stage0)] // SNAP c64d671 +#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { /// Drops the `Rc`. @@ -425,6 +511,61 @@ impl Drop for Rc { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for Rc { + /// Drops the `Rc`. + /// + /// This will decrement the strong reference count. If the strong reference + /// count becomes zero and the only other references are `Weak` ones, + /// `drop`s the inner value. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// { + /// let five = Rc::new(5); + /// + /// // stuff + /// + /// drop(five); // explicit drop + /// } + /// { + /// let five = Rc::new(5); + /// + /// // stuff + /// + /// } // implicit drop + /// ``` + fn drop(&mut self) { + unsafe { + let ptr = *self._ptr; + if !(*(&ptr as *const _ as *const *const ())).is_null() { + self.dec_strong(); + if self.strong() == 0 { + // destroy the contained object + drop_in_place(&mut (*ptr).value); + + // remove the implicit "strong weak" pointer now that we've + // destroyed the contents. + self.dec_weak(); + + if self.weak() == 0 { + deallocate(ptr as *mut u8, + size_of_val(&*ptr), + min_align_of_val(&*ptr)) + } + } + } + } + } +} + +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Rc { @@ -449,6 +590,31 @@ impl Clone for Rc { Rc { _ptr: self._ptr } } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Rc { + + /// Makes a clone of the `Rc`. + /// + /// When you clone an `Rc`, it will create another pointer to the data and + /// increase the strong reference counter. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// five.clone(); + /// ``` + #[inline] + fn clone(&self) -> Rc { + self.inc_strong(); + Rc { _ptr: self._ptr } + } +} #[stable(feature = "rust1", since = "1.0.0")] impl Default for Rc { @@ -610,27 +776,50 @@ impl Ord for Rc { fn cmp(&self, other: &Rc) -> Ordering { (**self).cmp(&**other) } } -// FIXME (#18248) Make `T` `Sized?` +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Hash for Rc { fn hash(&self, state: &mut H) { (**self).hash(state); } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for Rc { + fn hash(&self, state: &mut H) { + (**self).hash(state); + } +} +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Rc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Rc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Rc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Rc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Pointer for Rc { @@ -645,6 +834,7 @@ impl fmt::Pointer for Rc { /// dropped. /// /// See the [module level documentation](./index.html) for more. +#[cfg(stage0)] #[unsafe_no_drop_flag] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] @@ -653,12 +843,28 @@ pub struct Weak { // field accesses of the contained type via Deref _ptr: NonZero<*mut RcBox>, } +#[cfg(not(stage0))] +#[unsafe_no_drop_flag] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +pub struct Weak { + // FIXME #12808: strange names to try to avoid interfering with + // field accesses of the contained type via Deref + _ptr: NonZero<*mut RcBox>, +} +#[cfg(stage0)] impl !marker::Send for Weak {} +#[cfg(not(stage0))] +impl !marker::Send for Weak {} +#[cfg(stage0)] impl !marker::Sync for Weak {} +#[cfg(not(stage0))] +impl !marker::Sync for Weak {} +#[cfg(stage0)] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] impl Weak { @@ -691,7 +897,42 @@ impl Weak { } } } +#[cfg(not(stage0))] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +impl Weak { + /// Upgrades a weak reference to a strong reference. + /// + /// Upgrades the `Weak` reference to an `Rc`, if possible. + /// + /// Returns `None` if there were no strong references and the data was + /// destroyed. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let five = Rc::new(5); + /// + /// let weak_five = five.downgrade(); + /// + /// let strong_five: Option> = weak_five.upgrade(); + /// ``` + pub fn upgrade(&self) -> Option> { + if self.strong() == 0 { + None + } else { + self.inc_strong(); + Some(Rc { _ptr: self._ptr }) + } + } +} + +#[cfg(stage0)] // SNAP c64d671 +#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { /// Drops the `Weak`. @@ -736,6 +977,53 @@ impl Drop for Weak { } } +#[cfg(not(stage0))] // SNAP c64d671 +#[unsafe_destructor] +#[stable(feature = "rust1", since = "1.0.0")] +impl Drop for Weak { + /// Drops the `Weak`. + /// + /// This will decrement the weak reference count. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// { + /// let five = Rc::new(5); + /// let weak_five = five.downgrade(); + /// + /// // stuff + /// + /// drop(weak_five); // explicit drop + /// } + /// { + /// let five = Rc::new(5); + /// let weak_five = five.downgrade(); + /// + /// // stuff + /// + /// } // implicit drop + /// ``` + fn drop(&mut self) { + unsafe { + let ptr = *self._ptr; + if !(*(&ptr as *const _ as *const *const ())).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(ptr as *mut u8, size_of_val(&*ptr), + min_align_of_val(&*ptr)) + } + } + } + } +} + +#[cfg(stage0)] #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] impl Clone for Weak { @@ -760,14 +1048,48 @@ impl Clone for Weak { Weak { _ptr: self._ptr } } } +#[cfg(not(stage0))] +#[unstable(feature = "alloc", + reason = "Weak pointers may not belong in this module.")] +impl Clone for Weak { + + /// Makes a clone of the `Weak`. + /// + /// This increases the weak reference count. + /// + /// # Examples + /// + /// ``` + /// # #![feature(alloc)] + /// use std::rc::Rc; + /// + /// let weak_five = Rc::new(5).downgrade(); + /// + /// weak_five.clone(); + /// ``` + #[inline] + fn clone(&self) -> Weak { + self.inc_weak(); + Weak { _ptr: self._ptr } + } +} +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for Weak { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "(Weak)") } } +#[cfg(not(stage0))] +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Weak { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "(Weak)") + } +} +#[cfg(stage0)] #[doc(hidden)] trait RcBoxPtr { fn inner(&self) -> &RcBox; @@ -790,7 +1112,31 @@ trait RcBoxPtr { #[inline] fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } } +#[cfg(not(stage0))] +#[doc(hidden)] +trait RcBoxPtr { + fn inner(&self) -> &RcBox; + + #[inline] + fn strong(&self) -> usize { self.inner().strong.get() } + + #[inline] + fn inc_strong(&self) { self.inner().strong.set(self.strong() + 1); } + + #[inline] + fn dec_strong(&self) { self.inner().strong.set(self.strong() - 1); } + + #[inline] + fn weak(&self) -> usize { self.inner().weak.get() } + + #[inline] + fn inc_weak(&self) { self.inner().weak.set(self.weak() + 1); } + + #[inline] + fn dec_weak(&self) { self.inner().weak.set(self.weak() - 1); } +} +#[cfg(stage0)] impl RcBoxPtr for Rc { #[inline(always)] fn inner(&self) -> &RcBox { @@ -799,12 +1145,27 @@ impl RcBoxPtr for Rc { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - assume(!self._ptr.is_null()); + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); + &(**self._ptr) + } + } +} +#[cfg(not(stage0))] +impl RcBoxPtr for Rc { + #[inline(always)] + fn inner(&self) -> &RcBox { + unsafe { + // Safe to assume this here, as if it weren't true, we'd be breaking + // the contract anyway. + // This allows the null check to be elided in the destructor if we + // manipulated the reference count in the same function. + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); &(**self._ptr) } } } +#[cfg(stage0)] impl RcBoxPtr for Weak { #[inline(always)] fn inner(&self) -> &RcBox { @@ -813,7 +1174,21 @@ impl RcBoxPtr for Weak { // the contract anyway. // This allows the null check to be elided in the destructor if we // manipulated the reference count in the same function. - assume(!self._ptr.is_null()); + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); + &(**self._ptr) + } + } +} +#[cfg(not(stage0))] +impl RcBoxPtr for Weak { + #[inline(always)] + fn inner(&self) -> &RcBox { + unsafe { + // Safe to assume this here, as if it weren't true, we'd be breaking + // the contract anyway. + // This allows the null check to be elided in the destructor if we + // manipulated the reference count in the same function. + assume(!(*(&self._ptr as *const _ as *const *const ())).is_null()); &(**self._ptr) } } -- cgit 1.4.1-3-g733a5 From 03d4d5f80ed1d9e168869bdb244e4fef67b7d3d0 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Mon, 20 Apr 2015 10:52:26 +1200 Subject: Fix a bunch of bugs * segfault due to not copying drop flag when coercing * fat pointer casts * segfault due to not checking drop flag properly * debuginfo for DST smart pointers * unreachable code in drop glue --- src/liballoc/rc.rs | 6 +++-- src/librustc/middle/ty.rs | 3 +-- src/librustc_trans/trans/adt.rs | 14 ++++++---- src/librustc_trans/trans/expr.rs | 49 +++++++++++++++++++++++------------ src/librustc_trans/trans/glue.rs | 13 +++------- src/librustc_trans/trans/machine.rs | 3 ++- src/librustc_typeck/check/cast.rs | 17 ++++++------ src/test/compile-fail/fat-ptr-cast.rs | 12 +++------ src/test/compile-fail/issue-22289.rs | 2 +- src/test/run-pass/fat-ptr-cast.rs | 49 +++++++++++++++++++++++++++++++++++ 10 files changed, 114 insertions(+), 54 deletions(-) create mode 100644 src/test/run-pass/fat-ptr-cast.rs (limited to 'src/liballoc/rc.rs') diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 4e8a7e8bfc9..837cf590024 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -544,7 +544,8 @@ impl Drop for Rc { fn drop(&mut self) { unsafe { let ptr = *self._ptr; - if !(*(&ptr as *const _ as *const *const ())).is_null() { + if !(*(&ptr as *const _ as *const *const ())).is_null() && + ptr as usize != mem::POST_DROP_USIZE { self.dec_strong(); if self.strong() == 0 { // destroy the contained object @@ -1010,7 +1011,8 @@ impl Drop for Weak { fn drop(&mut self) { unsafe { let ptr = *self._ptr; - if !(*(&ptr as *const _ as *const *const ())).is_null() { + if !(*(&ptr as *const _ as *const *const ())).is_null() && + ptr as usize != mem::POST_DROP_USIZE { self.dec_weak(); // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 961f8a79324..5a84edd3cdf 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -5606,8 +5606,7 @@ impl DtorKind { } } -/* If struct_id names a struct with a dtor, return Some(the dtor's id). - Otherwise return none. */ +/* If struct_id names a struct with a dtor. */ pub fn ty_dtor(cx: &ctxt, struct_id: DefId) -> DtorKind { match cx.destructor_for_type.borrow().get(&struct_id) { Some(&method_def_id) => { diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index 001de615fb1..17c9fa24818 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -141,7 +141,8 @@ pub fn represent_node<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, /// Decides how to represent a given type. pub fn represent_type<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, - t: Ty<'tcx>) -> Rc> { + t: Ty<'tcx>) + -> Rc> { debug!("Representing: {}", ty_to_string(cx.tcx(), t)); match cx.adt_reprs().borrow().get(&t) { Some(repr) => return repr.clone(), @@ -216,7 +217,9 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, }).collect::>(); let packed = ty::lookup_packed(cx.tcx(), def_id); let dtor = ty::ty_dtor(cx.tcx(), def_id).has_drop_flag(); - if dtor { ftys.push(cx.tcx().dtor_type()); } + if dtor { + ftys.push(cx.tcx().dtor_type()); + } Univariant(mk_struct(cx, &ftys[..], packed, t), dtor_to_init_u8(dtor)) } @@ -517,8 +520,7 @@ fn mk_struct<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, -> Struct<'tcx> { let sized = tys.iter().all(|&ty| type_is_sized(cx.tcx(), ty)); let lltys : Vec = if sized { - tys.iter() - .map(|&ty| type_of::sizing_type_of(cx, ty)).collect() + tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect() } else { tys.iter().filter(|&ty| type_is_sized(cx.tcx(), *ty)) .map(|&ty| type_of::sizing_type_of(cx, ty)).collect() @@ -1060,7 +1062,9 @@ pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } /// Access the struct drop flag, if present. -pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>, val: ValueRef) +pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, + r: &Repr<'tcx>, + val: ValueRef) -> datum::DatumBlock<'blk, 'tcx, datum::Expr> { let tcx = bcx.tcx(); diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 0343571562f..4018df0da47 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -58,7 +58,7 @@ use middle::check_const; use middle::def; use middle::lang_items::CoerceUnsizedTraitLangItem; use middle::mem_categorization::Typer; -use middle::subst::{Subst, Substs, VecPerParamSpace}; +use middle::subst::{Substs, VecPerParamSpace}; use middle::traits; use trans::{_match, adt, asm, base, callee, closure, consts, controlflow}; use trans::base::*; @@ -476,8 +476,8 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } // This can be extended to enums and tuples in the future. - // (&ty::ty_enum(def_id_a, substs_a), &ty::ty_enum(def_id_b, substs_b)) | - (&ty::ty_struct(def_id_a, substs_a), &ty::ty_struct(def_id_b, substs_b)) => { + // (&ty::ty_enum(def_id_a, _), &ty::ty_enum(def_id_b, _)) | + (&ty::ty_struct(def_id_a, _), &ty::ty_struct(def_id_b, _)) => { assert_eq!(def_id_a, def_id_b); // The target is already by-ref because it's to be written to. @@ -504,35 +504,41 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; let repr_source = adt::represent_type(bcx.ccx(), source.ty); + let src_fields = match &*repr_source { + &adt::Repr::Univariant(ref s, _) => &s.fields, + _ => bcx.sess().span_bug(span, + &format!("Non univariant struct? (repr_source: {:?})", + repr_source)), + }; let repr_target = adt::represent_type(bcx.ccx(), target.ty); - let fields = ty::lookup_struct_fields(bcx.tcx(), def_id_a); + let target_fields = match &*repr_target { + &adt::Repr::Univariant(ref s, _) => &s.fields, + _ => bcx.sess().span_bug(span, + &format!("Non univariant struct? (repr_target: {:?})", + repr_target)), + }; let coerce_index = match kind { ty::CustomCoerceUnsized::Struct(i) => i }; - assert!(coerce_index < fields.len()); + assert!(coerce_index < src_fields.len() && src_fields.len() == target_fields.len()); - for (i, field) in fields.iter().enumerate() { + let iter = src_fields.iter().zip(target_fields.iter()).enumerate(); + for (i, (src_ty, target_ty)) in iter { let ll_source = adt::trans_field_ptr(bcx, &repr_source, source.val, 0, i); let ll_target = adt::trans_field_ptr(bcx, &repr_target, target.val, 0, i); - let ty = ty::lookup_field_type_unsubstituted(bcx.tcx(), - def_id_a, - field.id); - let field_source = ty.subst(bcx.tcx(), substs_a); - let field_target = ty.subst(bcx.tcx(), substs_b); - // If this is the field we need to coerce, recurse on it. if i == coerce_index { coerce_unsized(bcx, span, - Datum::new(ll_source, field_source, + Datum::new(ll_source, src_ty, Rvalue::new(ByRef)), - Datum::new(ll_target, field_target, + Datum::new(ll_target, target_ty, Rvalue::new(ByRef))); } else { // Otherwise, simply copy the data from the source. - assert_eq!(field_source, field_target); - memcpy_ty(bcx, ll_target, ll_source, field_source); + assert_eq!(src_ty, target_ty); + memcpy_ty(bcx, ll_target, ll_source, src_ty); } } } @@ -2013,6 +2019,7 @@ fn float_cast(bcx: Block, #[derive(Copy, Clone, PartialEq, Debug)] pub enum cast_kind { cast_pointer, + cast_fat_ptr, cast_integral, cast_float, cast_enum, @@ -2027,7 +2034,7 @@ pub fn cast_type_kind<'tcx>(tcx: &ty::ctxt<'tcx>, t: Ty<'tcx>) -> cast_kind { if type_is_sized(tcx, mt.ty) { cast_pointer } else { - cast_other + cast_fat_ptr } } ty::ty_bare_fn(..) => cast_pointer, @@ -2103,10 +2110,18 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let llexpr = datum.to_llscalarish(bcx); PtrToInt(bcx, llexpr, ll_t_out) } + (cast_fat_ptr, cast_integral) => { + let data_ptr = Load(bcx, get_dataptr(bcx, datum.val)); + PtrToInt(bcx, data_ptr, ll_t_out) + } (cast_pointer, cast_pointer) => { let llexpr = datum.to_llscalarish(bcx); PointerCast(bcx, llexpr, ll_t_out) } + (cast_fat_ptr, cast_pointer) => { + let data_ptr = Load(bcx, get_dataptr(bcx, datum.val)); + PointerCast(bcx, data_ptr, ll_t_out) + } (cast_enum, cast_integral) | (cast_enum, cast_float) => { let mut bcx = bcx; diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs index fd1f22e1d9d..264957d3651 100644 --- a/src/librustc_trans/trans/glue.rs +++ b/src/librustc_trans/trans/glue.rs @@ -278,18 +278,14 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, - v0: ValueRef, + struct_data: ValueRef, dtor_did: ast::DefId, class_did: ast::DefId, substs: &subst::Substs<'tcx>) -> Block<'blk, 'tcx> { + assert!(type_is_sized(bcx.tcx(), t), "Precondition: caller must ensure t is sized"); + let repr = adt::represent_type(bcx.ccx(), t); - let struct_data = if type_is_sized(bcx.tcx(), t) { - v0 - } else { - let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]); - Load(bcx, llval) - }; let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data)); let loaded = load_ty(bcx, drop_flag.val, bcx.tcx().dtor_type()); let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type()); @@ -313,9 +309,8 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>, let drop_flag_dtor_needed = ICmp(bcx, llvm::IntEQ, loaded, init_val, DebugLoc::None); with_cond(bcx, drop_flag_dtor_needed, |cx| { - trans_struct_drop(cx, t, v0, dtor_did, class_did, substs) + trans_struct_drop(cx, t, struct_data, dtor_did, class_did, substs) }) - } pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, diff --git a/src/librustc_trans/trans/machine.rs b/src/librustc_trans/trans/machine.rs index ce37d38dc89..39bc547a1a7 100644 --- a/src/librustc_trans/trans/machine.rs +++ b/src/librustc_trans/trans/machine.rs @@ -101,7 +101,8 @@ pub fn llalign_of_min(cx: &CrateContext, ty: Type) -> llalign { pub fn llelement_offset(cx: &CrateContext, struct_ty: Type, element: usize) -> u64 { unsafe { - return llvm::LLVMOffsetOfElement(cx.td().lltd, struct_ty.to_ref(), + return llvm::LLVMOffsetOfElement(cx.td().lltd, + struct_ty.to_ref(), element as u32); } } diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index f0495436bc1..bfd159720c2 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -99,6 +99,7 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { let t_1_is_bare_fn = ty::type_is_bare_fn(t_1); let t_1_is_float = ty::type_is_floating_point(t_1); let t_1_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_1); + let t1_is_fat_ptr = fcx.type_is_fat_ptr(t_1, span); // casts to scalars other than `char` and `bare fn` are trivial let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn; @@ -170,18 +171,16 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { demand::coerce(fcx, e.span, t_1, &e); } } - } else if fcx.type_is_fat_ptr(t_e, span) != fcx.type_is_fat_ptr(t_1, span) { + } else if t1_is_fat_ptr { + // FIXME This should be allowed where the lefthandside is also a fat + // pointer and is the same kind of fat pointer, i.e., array to array, + // trait object to trait object. fcx.type_error_message(span, |actual| { - format!("illegal cast; cast to or from fat pointer: `{}` as `{}` \ - involving incompatible type.", - actual, fcx.infcx().ty_to_string(t_1)) + format!("cast to fat pointer: `{}` as `{}`", + actual, + fcx.infcx().ty_to_string(t_1)) }, t_e, None); } else if !(t_e_is_scalar && t_1_is_trivial) { - /* - If more type combinations should be supported than are - supported here, then file an enhancement issue and - record the issue number in this comment. - */ fcx.type_error_message(span, |actual| { format!("non-scalar cast: `{}` as `{}`", actual, diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs index 381dff36b7d..415785a1174 100644 --- a/src/test/compile-fail/fat-ptr-cast.rs +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -15,17 +15,13 @@ pub trait Trait {} fn main() { let a: &[i32] = &[1, 2, 3]; let b: Box<[i32]> = Box::new([1, 2, 3]); - let p = a as *const [i32]; - let q = a.as_ptr(); a as usize; //~ ERROR illegal cast b as usize; //~ ERROR illegal cast - p as usize; //~ ERROR illegal cast - // #22955 - q as *const [i32]; //~ ERROR illegal cast + let a: usize = 42; + a as *const [i32]; //~ ERROR cast to fat pointer: `usize` as `*const [i32]` - // #21397 - let t: *mut (Trait + 'static) = 0 as *mut _; //~ ERROR illegal cast - let mut fail: *const str = 0 as *const str; //~ ERROR illegal cast + let a: *const u8 = &42; + a as *const [u8]; //~ ERROR cast to fat pointer: `*const u8` as `*const [u8]` } diff --git a/src/test/compile-fail/issue-22289.rs b/src/test/compile-fail/issue-22289.rs index 5adea183bc9..1fdc8735714 100644 --- a/src/test/compile-fail/issue-22289.rs +++ b/src/test/compile-fail/issue-22289.rs @@ -9,5 +9,5 @@ // except according to those terms. fn main() { - 0 as &std::any::Any; //~ ERROR illegal cast + 0 as &std::any::Any; //~ ERROR cast to fat pointer: `i32` as `&core::any::Any` } diff --git a/src/test/run-pass/fat-ptr-cast.rs b/src/test/run-pass/fat-ptr-cast.rs new file mode 100644 index 00000000000..b7513da99c8 --- /dev/null +++ b/src/test/run-pass/fat-ptr-cast.rs @@ -0,0 +1,49 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(core)] + +use std::mem; +use std::raw; + +trait Foo { + fn foo(&self) {} +} + +struct Bar; + +impl Foo for Bar {} + +fn main() { + // Test we can turn a fat pointer to array back into a thin pointer. + let a: *const [i32] = &[1, 2, 3]; + let b = a as *const [i32; 2]; + unsafe { + assert!(*b == [1, 2]); + } + + // Test conversion to an address (usize). + let a: *const [i32; 3] = &[1, 2, 3]; + let b: *const [i32] = a; + assert!(a as usize == b as usize); + + // And conversion to a void pointer/address for trait objects too. + let a: *mut Foo = &mut Bar; + let b = a as *mut (); + let c = a as usize; + + let d = unsafe { + let r: raw::TraitObject = mem::transmute(a); + r.data + }; + + assert!(b == d); + assert!(c == d as usize); +} -- cgit 1.4.1-3-g733a5 From 5d4cce6cec7c0975263bbe6f4260167a772bfc89 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 12 May 2015 14:41:08 +1200 Subject: Rebasing --- src/liballoc/rc.rs | 4 -- src/libcore/cell.rs | 1 - src/libcore/ops.rs | 9 +++++ src/libcoretest/cell.rs | 23 +++++------ src/librustc/diagnostics.rs | 2 - src/librustc/middle/traits/select.rs | 7 ++-- src/librustc/middle/traits/util.rs | 2 +- src/librustc/middle/ty.rs | 2 +- src/librustc_trans/trans/debuginfo/metadata.rs | 8 ++-- src/librustc_trans/trans/expr.rs | 4 +- src/librustc_typeck/check/cast.rs | 55 ++++++++++++++------------ src/librustc_typeck/check/coercion.rs | 10 ++++- src/librustc_typeck/check/regionck.rs | 1 + src/librustc_typeck/coherence/mod.rs | 41 +++++++------------ src/librustc_typeck/coherence/orphan.rs | 2 +- src/librustc_typeck/diagnostics.rs | 6 +-- src/libstd/sync/mutex.rs | 23 +++++------ src/libstd/sync/rwlock.rs | 23 +++++------ src/test/compile-fail/fat-ptr-cast.rs | 4 +- 19 files changed, 118 insertions(+), 109 deletions(-) (limited to 'src/liballoc/rc.rs') diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 837cf590024..15d6e6fa960 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -460,7 +460,6 @@ impl Deref for Rc { } #[cfg(stage0)] // SNAP c64d671 -#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { /// Drops the `Rc`. @@ -512,7 +511,6 @@ impl Drop for Rc { } #[cfg(not(stage0))] // SNAP c64d671 -#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { /// Drops the `Rc`. @@ -933,7 +931,6 @@ impl Weak { } #[cfg(stage0)] // SNAP c64d671 -#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { /// Drops the `Weak`. @@ -979,7 +976,6 @@ impl Drop for Weak { } #[cfg(not(stage0))] // SNAP c64d671 -#[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { /// Drops the `Weak`. diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index bf5fdb973eb..45a80122104 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -707,5 +707,4 @@ impl UnsafeCell { #![allow(trivial_casts)] &self.value as *const T as *mut T } - } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 1a2473fda41..9396adc0fe5 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -1220,24 +1220,33 @@ pub trait CoerceUnsized { // Empty. } +// &mut T -> &mut U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} +// &mut T -> &U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} +// &mut T -> *mut U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} +// &mut T -> *const U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} +// &T -> &U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} +// &T -> *const U #[cfg(not(stage0))] // SNAP c64d671 impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} +// *mut T -> *mut U #[cfg(not(stage0))] // SNAP c64d671 impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} +// *mut T -> *const U #[cfg(not(stage0))] // SNAP c64d671 impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} +// *const T -> *const U #[cfg(not(stage0))] // SNAP c64d671 impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs index 0bd0b66318f..f02312b8641 100644 --- a/src/libcoretest/cell.rs +++ b/src/libcoretest/cell.rs @@ -172,14 +172,15 @@ fn unsafe_cell_unsized() { assert_eq!(unsafe { &mut *cell.get() }, comp); } -#[test] -fn refcell_unsized() { - let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]); - { - let b = &mut *cell.borrow_mut(); - b[0] = 4; - b[2] = 5; - } - let comp: &mut [i32] = &mut [4, 2, 5]; - assert_eq!(&*cell.borrow(), comp); -} +// FIXME(#25351) needs deeply nested coercions of DST structs. +// #[test] +// fn refcell_unsized() { +// let cell: &RefCell<[i32]> = &RefCell::new([1, 2, 3]); +// { +// let b = &mut *cell.borrow_mut(); +// b[0] = 4; +// b[2] = 5; +// } +// let comp: &mut [i32] = &mut [4, 2, 5]; +// assert_eq!(&*cell.borrow(), comp); +// } diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index c8788f76081..bb50d5110cb 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -808,8 +808,6 @@ register_diagnostics! { E0019, E0022, E0038, - E0079, // enum variant: expected signed integer constant - E0080, // enum variant: constant evaluation error E0109, E0110, E0134, diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 2541bba5d9a..a4ed73d7358 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -1369,7 +1369,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn assemble_candidates_for_unsizing(&mut self, obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>) { - // TODO is it Ok to skip the binder here? + // It is ok to skip past the higher-ranked binders here because the `match` + // below does not consider regions at all. let source = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder()); let target = self.infcx.shallow_resolve(obligation.predicate.0.input_types()[0]); @@ -1494,7 +1495,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &ClosureCandidate(..) | &FnPointerCandidate(..) | &BuiltinObjectCandidate(..) | - &&BuiltinUnsizeCandidate(..) | + &BuiltinUnsizeCandidate(..) | &DefaultImplObjectCandidate(..) | &BuiltinCandidate(..) => { // We have a where-clause so don't go around looking @@ -2498,7 +2499,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::lookup_field_type_unsubstituted(tcx, def_id, f.id) }).collect::>(); - // The last field of the structure has to exist and be a + // FIXME(#25351) The last field of the structure has to exist and be a // type parameter (for now, to avoid tracking edge cases). let i = if let Some(&ty::ty_param(p)) = fields.last().map(|ty| &ty.sty) { assert!(p.space == TypeSpace); diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index ea4bc029ed6..f30f8560b9f 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -377,7 +377,7 @@ pub fn predicate_for_trait_def<'tcx>( let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs(Substs::new_trait(ty_params, vec![], param_ty)) - }); + }; predicate_for_trait_ref(cause, trait_ref, recursion_depth) } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 5a84edd3cdf..9054cd65473 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4420,7 +4420,7 @@ pub fn deref<'tcx>(ty: Ty<'tcx>, explicit: bool) -> Option> { pub fn type_content<'tcx>(ty: Ty<'tcx>) -> Ty<'tcx> { match ty.sty { ty_uniq(ty) => ty, - ty_rptr(_, mt) |ty_ptr(mt) => mt.ty, + ty_rptr(_, mt) | ty_ptr(mt) => mt.ty, _ => ty } } diff --git a/src/librustc_trans/trans/debuginfo/metadata.rs b/src/librustc_trans/trans/debuginfo/metadata.rs index bd04bd7a754..ab86cd7cdde 100644 --- a/src/librustc_trans/trans/debuginfo/metadata.rs +++ b/src/librustc_trans/trans/debuginfo/metadata.rs @@ -1058,6 +1058,7 @@ impl MetadataCreationResult { } } +#[derive(Debug)] enum MemberOffset { FixedMemberOffset { bytes: usize }, // For ComputedMemberOffset, the offset is read from the llvm type definition. @@ -1066,6 +1067,7 @@ enum MemberOffset { // Description of a type member, which can either be a regular field (as in // structs or tuples) or an enum variant. +#[derive(Debug)] struct MemberDescription { name: String, llvm_type: Type, @@ -1163,13 +1165,13 @@ fn prepare_struct_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, span: Span) -> RecursiveTypeDescription<'tcx> { let struct_name = compute_debuginfo_type_name(cx, struct_type, false); - let struct_llvm_type = type_of::type_of(cx, struct_type); + let struct_llvm_type = type_of::in_memory_type_of(cx, struct_type); let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id); let struct_metadata_stub = create_struct_stub(cx, struct_llvm_type, - &struct_name[..], + &struct_name, unique_type_id, containing_scope); @@ -1299,7 +1301,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { set_members_of_composite_type(cx, variant_type_metadata, variant_llvm_type, - &member_descriptions[..]); + &member_descriptions); MemberDescription { name: "".to_string(), llvm_type: variant_llvm_type, diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 4018df0da47..270aacfe143 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -487,11 +487,11 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let trait_substs = Substs::erased(VecPerParamSpace::new(vec![target.ty], vec![source.ty], Vec::new())); - let trait_ref = ty::Binder(Rc::new(ty::TraitRef { + let trait_ref = ty::Binder(ty::TraitRef { def_id: langcall(bcx, Some(span), "coercion", CoerceUnsizedTraitLangItem), substs: bcx.tcx().mk_substs(trait_substs) - })); + }); let kind = match fulfill_obligation(bcx.ccx(), span, trait_ref) { traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => { diff --git a/src/librustc_typeck/check/cast.rs b/src/librustc_typeck/check/cast.rs index bfd159720c2..bc6159c0cff 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/src/librustc_typeck/check/cast.rs @@ -60,28 +60,29 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { let e = &cast.expr; let t_e = structurally_resolved_type(fcx, span, cast.expr_ty); let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty); + let tcx = fcx.tcx(); // Check for trivial casts. if !ty::type_has_ty_infer(t_1) { if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) { if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) { - fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS, - e.id, - span, - format!("trivial numeric cast: `{}` as `{}`. Cast can be \ - replaced by coercion, this might require type \ - ascription or a temporary variable", - fcx.infcx().ty_to_string(t_e), - fcx.infcx().ty_to_string(t_1))); + tcx.sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS, + e.id, + span, + format!("trivial numeric cast: `{}` as `{}`. Cast can be \ + replaced by coercion, this might require type \ + ascription or a temporary variable", + fcx.infcx().ty_to_string(t_e), + fcx.infcx().ty_to_string(t_1))); } else { - fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS, - e.id, - span, - format!("trivial cast: `{}` as `{}`. Cast can be \ - replaced by coercion, this might require type \ - ascription or a temporary variable", - fcx.infcx().ty_to_string(t_e), - fcx.infcx().ty_to_string(t_1))); + tcx.sess.add_lint(lint::builtin::TRIVIAL_CASTS, + e.id, + span, + format!("trivial cast: `{}` as `{}`. Cast can be \ + replaced by coercion, this might require type \ + ascription or a temporary variable", + fcx.infcx().ty_to_string(t_e), + fcx.infcx().ty_to_string(t_1))); } return; } @@ -91,14 +92,14 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { let t_e_is_scalar = ty::type_is_scalar(t_e); let t_e_is_integral = ty::type_is_integral(t_e); let t_e_is_float = ty::type_is_floating_point(t_e); - let t_e_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_e); + let t_e_is_c_enum = ty::type_is_c_like_enum(tcx, t_e); let t_1_is_scalar = ty::type_is_scalar(t_1); let t_1_is_integral = ty::type_is_integral(t_1); let t_1_is_char = ty::type_is_char(t_1); let t_1_is_bare_fn = ty::type_is_bare_fn(t_1); let t_1_is_float = ty::type_is_floating_point(t_1); - let t_1_is_c_enum = ty::type_is_c_like_enum(fcx.tcx(), t_1); + let t_1_is_c_enum = ty::type_is_c_like_enum(tcx, t_1); let t1_is_fat_ptr = fcx.type_is_fat_ptr(t_1, span); // casts to scalars other than `char` and `bare fn` are trivial @@ -114,7 +115,7 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { }, t_e, None); } } else if t_1.sty == ty::ty_bool { - span_err!(fcx.tcx().sess, span, E0054, + span_err!(tcx.sess, span, E0054, "cannot cast as `bool`, compare with zero instead"); } else if t_e_is_float && (t_1_is_scalar || t_1_is_c_enum) && !(t_1_is_integral || t_1_is_float) { @@ -174,12 +175,16 @@ pub fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) { } else if t1_is_fat_ptr { // FIXME This should be allowed where the lefthandside is also a fat // pointer and is the same kind of fat pointer, i.e., array to array, - // trait object to trait object. - fcx.type_error_message(span, |actual| { - format!("cast to fat pointer: `{}` as `{}`", - actual, - fcx.infcx().ty_to_string(t_1)) - }, t_e, None); + // trait object to trait object. That is a bit looser than the current + // rquirement that they are pointers to the same type. + if !(fcx.type_is_fat_ptr(t_e, span) && + ty::deref(t_1, true).unwrap().ty == ty::deref(t_e, true).unwrap().ty) { + fcx.type_error_message(span, |actual| { + format!("cast to fat pointer: `{}` as `{}`", + actual, + fcx.infcx().ty_to_string(t_1)) + }, t_e, None); + } } else if !(t_e_is_scalar && t_1_is_trivial) { fcx.type_error_message(span, |actual| { format!("non-scalar cast: `{}` as `{}`", diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index d33553f3859..dd63a512ae3 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -285,14 +285,19 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Create an obligation for `Source: CoerceUnsized`. let cause = ObligationCause::misc(self.origin.span(), self.fcx.body_id); - queue.push_back(predicate_for_trait_def(self.tcx(), cause, coerce_unsized_did, - 0, source, vec![target])); + queue.push_back(predicate_for_trait_def(self.tcx(), + cause, + coerce_unsized_did, + 0, + source, + vec![target])); // Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid // emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where // inference might unify those two inner type variables later. let traits = [coerce_unsized_did, unsize_did]; while let Some(obligation) = queue.pop_front() { + debug!("coerce_unsized resolve step: {}", obligation.repr(self.tcx())); let trait_ref = match obligation.predicate { ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => { tr.clone() @@ -305,6 +310,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match selcx.select(&obligation.with(trait_ref)) { // Uncertain or unimplemented. Ok(None) | Err(traits::Unimplemented) => { + debug!("coerce_unsized: early return - can't prove obligation"); return Err(ty::terr_mismatch); } diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 337088c313d..090d111b62b 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -85,6 +85,7 @@ use astconv::AstConv; use check::dropck; use check::FnCtxt; +use middle::free_region::FreeRegionMap; use middle::implicator; use middle::mem_categorization as mc; use middle::region::CodeExtent; diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index c6e0bb676f7..58ad8ce8628 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -29,6 +29,7 @@ use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int}; use middle::ty::{ty_uint, ty_closure, ty_uniq, ty_bare_fn}; use middle::ty::ty_projection; use middle::ty; +use middle::free_region::FreeRegionMap; use CrateCtxt; use middle::infer::{self, InferCtxt, new_infer_ctxt}; use std::cell::RefCell; @@ -439,32 +440,19 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { } }; - let trait_impls = match tcx.trait_impls - .borrow() - .get(&coerce_unsized_trait) - .cloned() { - None => { - debug!("check_implementations_of_coerce_unsized(): no types \ - with implementations of `CoerceUnsized` found"); - return - } - Some(found_impls) => found_impls - }; + let trait_def = ty::lookup_trait_def(tcx, coerce_unsized_trait); - // Clone first to avoid a double borrow error. - let trait_impls = trait_impls.borrow().clone(); - - for &impl_did in &trait_impls { + trait_def.for_each_impl(tcx, |impl_did| { debug!("check_implementations_of_coerce_unsized: impl_did={}", impl_did.repr(tcx)); if impl_did.krate != ast::LOCAL_CRATE { debug!("check_implementations_of_coerce_unsized(): impl not \ in this crate"); - continue + return; } - let source = self.get_self_type_for_implementation(impl_did).ty; + let source = ty::lookup_item_type(tcx, impl_did).ty; let trait_ref = ty::impl_id_to_trait_ref(self.crate_context.tcx, impl_did.node); let target = *trait_ref.substs.types.get(subst::TypeSpace, 0); @@ -507,12 +495,12 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { if def_id_a != def_id_b { let source_path = ty::item_path_str(tcx, def_id_a); let target_path = ty::item_path_str(tcx, def_id_b); - span_err!(tcx.sess, span, E0373, + span_err!(tcx.sess, span, E0377, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures with the same \ definition; expected {}, found {}", source_path, target_path); - continue; + return; } let origin = infer::Misc(span); @@ -532,7 +520,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures with one field \ being coerced, none found"); - continue; + return; } else if diff_fields.len() > 1 { span_err!(tcx.sess, span, E0375, "the trait `CoerceUnsized` may only be implemented \ @@ -549,7 +537,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { a.repr(tcx), b.repr(tcx)) }).collect::>().connect(", ")); - continue; + return; } let (i, a, b) = diff_fields[0]; @@ -561,7 +549,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { span_err!(tcx.sess, span, E0376, "the trait `CoerceUnsized` may only be implemented \ for a coercion between structures"); - continue; + return; } }; @@ -578,14 +566,15 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { traits::report_fulfillment_errors(&infcx, &errors); } - // Finally, resolve all regions. This catches wily misuses of lifetime - // parameters. - infcx.resolve_regions_and_report_errors(impl_did.node); + // Finally, resolve all regions. + let mut free_regions = FreeRegionMap::new(); + free_regions.relate_free_regions_from_predicates(tcx, ¶m_env.caller_bounds); + infcx.resolve_regions_and_report_errors(&free_regions, impl_did.node); if let Some(kind) = kind { tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind); } - } + }); } } diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs index c75a0d816a8..4c9fe6492e9 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/src/librustc_typeck/coherence/orphan.rs @@ -323,7 +323,7 @@ impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> { return; } if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() { - span_err!(self.tcx.sess, item.span, E0323, + span_err!(self.tcx.sess, item.span, E0328, "explicit impls for the `Unsize` trait are not permitted"); return; } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index ac10a4e7121..e92779641c9 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -452,13 +452,13 @@ register_diagnostics! { E0369, // binary operation `` cannot be applied to types E0371, // impl Trait for Trait is illegal E0372, // impl Trait for Trait where Trait is not object safe - E0373, // the trait `CoerceUnsized` may only be implemented for a coercion - // between structures with the same definition E0374, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with one field being coerced, none found E0375, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures with one field being coerced, but multiple // fields need coercions - E0376 // the trait `CoerceUnsized` may only be implemented for a coercion + E0376, // the trait `CoerceUnsized` may only be implemented for a coercion // between structures + E0377 // the trait `CoerceUnsized` may only be implemented for a coercion + // between structures with the same definition } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index febf5f1b183..f9ed7c863d1 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -531,15 +531,16 @@ mod tests { assert_eq!(*lock, 2); } - #[test] - fn test_mutex_unsized() { - let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); - { - let b = &mut *mutex.lock().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*mutex.lock().unwrap(), comp); - } + // FIXME(#25351) needs deeply nested coercions of DST structs. + // #[test] + // fn test_mutex_unsized() { + // let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); + // { + // let b = &mut *mutex.lock().unwrap(); + // b[0] = 4; + // b[2] = 5; + // } + // let comp: &[i32] = &[4, 2, 5]; + // assert_eq!(&*mutex.lock().unwrap(), comp); + // } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 625377df7d6..36f6fbf3b72 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -573,17 +573,18 @@ mod tests { assert_eq!(*lock, 2); } - #[test] - fn test_rwlock_unsized() { - let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); - { - let b = &mut *rw.write().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*rw.read().unwrap(), comp); - } + // FIXME(#25351) needs deeply nested coercions of DST structs. + // #[test] + // fn test_rwlock_unsized() { + // let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); + // { + // let b = &mut *rw.write().unwrap(); + // b[0] = 4; + // b[2] = 5; + // } + // let comp: &[i32] = &[4, 2, 5]; + // assert_eq!(&*rw.read().unwrap(), comp); + // } #[test] fn test_rwlock_try_write() { diff --git a/src/test/compile-fail/fat-ptr-cast.rs b/src/test/compile-fail/fat-ptr-cast.rs index 415785a1174..2099424b05c 100644 --- a/src/test/compile-fail/fat-ptr-cast.rs +++ b/src/test/compile-fail/fat-ptr-cast.rs @@ -16,8 +16,8 @@ fn main() { let a: &[i32] = &[1, 2, 3]; let b: Box<[i32]> = Box::new([1, 2, 3]); - a as usize; //~ ERROR illegal cast - b as usize; //~ ERROR illegal cast + a as usize; //~ ERROR non-scalar cast + b as usize; //~ ERROR non-scalar cast let a: usize = 42; a as *const [i32]; //~ ERROR cast to fat pointer: `usize` as `*const [i32]` -- cgit 1.4.1-3-g733a5 From b799cd83cc797b580be2d1492e6ae014848636ee Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 13 May 2015 15:05:02 +1200 Subject: Remove SNAP comments --- src/liballoc/boxed.rs | 6 +++--- src/liballoc/rc.rs | 10 +++++----- src/libcore/marker.rs | 2 +- src/libcore/mem.rs | 8 ++++---- src/libcore/nonzero.rs | 4 ++-- src/libcore/ops.rs | 22 +++++++++++----------- src/librustc_typeck/diagnostics.rs | 1 - 7 files changed, 26 insertions(+), 27 deletions(-) (limited to 'src/liballoc/rc.rs') diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 757c799d85c..35732dacd44 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -62,9 +62,9 @@ use core::ops::{Deref, DerefMut}; use core::ptr::{Unique}; use core::raw::{TraitObject}; -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] use core::marker::Unsize; -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] use core::ops::CoerceUnsized; /// A value that represents the heap. This is the default place that the `box` @@ -396,5 +396,5 @@ impl<'a,A,R> FnOnce for Box+Send+'a> { } } -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: ?Sized> CoerceUnsized> for Box {} diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index 15d6e6fa960..f2b83fdeefa 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -228,7 +228,7 @@ impl !marker::Sync for Rc {} #[cfg(not(stage0))] impl !marker::Sync for Rc {} -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: ?Sized> CoerceUnsized> for Rc {} impl Rc { @@ -459,7 +459,7 @@ impl Deref for Rc { } } -#[cfg(stage0)] // SNAP c64d671 +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { /// Drops the `Rc`. @@ -510,7 +510,7 @@ impl Drop for Rc { } } -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Rc { /// Drops the `Rc`. @@ -930,7 +930,7 @@ impl Weak { } } -#[cfg(stage0)] // SNAP c64d671 +#[cfg(stage0)] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { /// Drops the `Weak`. @@ -975,7 +975,7 @@ impl Drop for Weak { } } -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[stable(feature = "rust1", since = "1.0.0")] impl Drop for Weak { /// Drops the `Weak`. diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index 968f68a78a7..5909c5cc30e 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -55,7 +55,7 @@ pub trait Sized { /// Types that can be "unsized" to a dynamically sized type. #[unstable(feature = "core")] -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[lang="unsize"] pub trait Unsize { // Empty. diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index bb94cd886d7..173b73fdb09 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -95,7 +95,7 @@ pub fn size_of() -> usize { /// /// assert_eq!(4, mem::size_of_val(&5i32)); /// ``` -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn size_of_val(val: &T) -> usize { @@ -111,7 +111,7 @@ pub fn size_of_val(val: &T) -> usize { /// /// assert_eq!(4, mem::size_of_val(&5i32)); /// ``` -#[cfg(stage0)] // SNAP c64d671 +#[cfg(stage0)] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn size_of_val(_val: &T) -> usize { @@ -144,7 +144,7 @@ pub fn min_align_of() -> usize { /// /// assert_eq!(4, mem::min_align_of_val(&5i32)); /// ``` -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn min_align_of_val(val: &T) -> usize { @@ -160,7 +160,7 @@ pub fn min_align_of_val(val: &T) -> usize { /// /// assert_eq!(4, mem::min_align_of_val(&5i32)); /// ``` -#[cfg(stage0)] // SNAP c64d671 +#[cfg(stage0)] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn min_align_of_val(_val: &T) -> usize { diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 85957382826..59819fd500d 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -12,7 +12,7 @@ use marker::Sized; use ops::Deref; -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] use ops::CoerceUnsized; /// Unsafe trait to indicate what types are usable with the NonZero struct @@ -57,5 +57,5 @@ impl Deref for NonZero { } } -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: Zeroable> CoerceUnsized> for NonZero {} diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 9396adc0fe5..f16614cfd09 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -70,7 +70,7 @@ use marker::Sized; use fmt; -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] use marker::Unsize; /// The `Drop` trait is used to run some code when a value goes out of scope. This @@ -1214,39 +1214,39 @@ mod impls { /// Trait that indicates that this is a pointer or a wrapper for one, /// where unsizing can be performed on the pointee. #[unstable(feature = "core")] -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] #[lang="coerce_unsized"] pub trait CoerceUnsized { // Empty. } // &mut T -> &mut U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {} // &mut T -> &U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b mut T {} // &mut T -> *mut U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*mut U> for &'a mut T {} // &mut T -> *const U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a mut T {} // &T -> &U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, 'b: 'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} // &T -> *const U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl<'a, T: ?Sized+Unsize, U: ?Sized> CoerceUnsized<*const U> for &'a T {} // *mut T -> *mut U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} // *mut T -> *const U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: ?Sized> CoerceUnsized<*const U> for *mut T {} // *const T -> *const U -#[cfg(not(stage0))] // SNAP c64d671 +#[cfg(not(stage0))] impl, U: ?Sized> CoerceUnsized<*const U> for *const T {} diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index e92779641c9..8375061aa09 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -309,7 +309,6 @@ register_diagnostics! { E0034, // multiple applicable methods in scope E0035, // does not take type parameters E0036, // incorrect number of type parameters given for this method - E0038, // cannot convert to a trait object because trait is not object-safe E0040, // explicit use of destructor method E0044, // foreign items may not have type parameters E0045, // variadic function must have C calling convention -- cgit 1.4.1-3-g733a5