Auto merge of #23423 - nikomatsakis:issue-18737-trait-subtyping, r=nrc
This upcast coercion currently never requires vtable changes. It should be generalized. This is a [breaking-change] -- if you have an impl on an object type like `impl SomeTrait`, then this will no longer be applicable to object types like `SomeTrait+Send`. In the standard library, this primarily affected `Any`, and this PR adds impls for `Any+Send` as to keep the API the same in practice. An alternate workaround is to use UFCS form or standalone fns. For more details, see <https://github.com/rust-lang/rust/issues/18737#issuecomment-78450798>. r? @nrc
This commit is contained in:
@@ -241,7 +241,7 @@ pub trait BoxAny {
|
|||||||
/// Returns the boxed value if it is of type `T`, or
|
/// Returns the boxed value if it is of type `T`, or
|
||||||
/// `Err(Self)` if it isn't.
|
/// `Err(Self)` if it isn't.
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
fn downcast<T: 'static>(self) -> Result<Box<T>, Self>;
|
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
@@ -264,6 +264,15 @@ impl BoxAny for Box<Any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl BoxAny for Box<Any+Send> {
|
||||||
|
#[inline]
|
||||||
|
fn downcast<T: 'static>(self) -> Result<Box<T>, Box<Any>> {
|
||||||
|
<Box<Any>>::downcast(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
impl<T: fmt::Display + ?Sized> fmt::Display for Box<T> {
|
impl<T: fmt::Display + ?Sized> fmt::Display for Box<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
|||||||
@@ -71,6 +71,7 @@
|
|||||||
|
|
||||||
#![stable(feature = "rust1", since = "1.0.0")]
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
|
use marker::Send;
|
||||||
use mem::transmute;
|
use mem::transmute;
|
||||||
use option::Option::{self, Some, None};
|
use option::Option::{self, Some, None};
|
||||||
use raw::TraitObject;
|
use raw::TraitObject;
|
||||||
@@ -154,6 +155,31 @@ impl Any {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
impl Any+Send {
|
||||||
|
/// Forwards to the method defined on the type `Any`.
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[inline]
|
||||||
|
pub fn is<T: 'static>(&self) -> bool {
|
||||||
|
Any::is::<T>(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Forwards to the method defined on the type `Any`.
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[inline]
|
||||||
|
pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
|
||||||
|
Any::downcast_ref::<T>(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Forwards to the method defined on the type `Any`.
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
#[inline]
|
||||||
|
pub fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
|
||||||
|
Any::downcast_mut::<T>(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// TypeID and its methods
|
// TypeID and its methods
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -1102,6 +1102,11 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
|
|||||||
this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty)))
|
this.emit_enum_variant_arg(1, |this| Ok(this.emit_ty(ecx, self_ty)))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ty::UnsizeUpcast(target_ty) => {
|
||||||
|
this.emit_enum_variant("UnsizeUpcast", 3, 1, |this| {
|
||||||
|
this.emit_enum_variant_arg(0, |this| Ok(this.emit_ty(ecx, target_ty)))
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1707,7 +1712,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
|||||||
fn read_unsize_kind<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
fn read_unsize_kind<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
|
||||||
-> ty::UnsizeKind<'tcx> {
|
-> ty::UnsizeKind<'tcx> {
|
||||||
self.read_enum("UnsizeKind", |this| {
|
self.read_enum("UnsizeKind", |this| {
|
||||||
let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable"];
|
let variants = &["UnsizeLength", "UnsizeStruct", "UnsizeVtable", "UnsizeUpcast"];
|
||||||
this.read_enum_variant(variants, |this, i| {
|
this.read_enum_variant(variants, |this, i| {
|
||||||
Ok(match i {
|
Ok(match i {
|
||||||
0 => {
|
0 => {
|
||||||
@@ -1741,6 +1746,11 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
|
|||||||
this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap();
|
this.read_enum_variant_arg(1, |this| Ok(this.read_ty(dcx))).unwrap();
|
||||||
ty::UnsizeVtable(ty_trait, self_ty)
|
ty::UnsizeVtable(ty_trait, self_ty)
|
||||||
}
|
}
|
||||||
|
3 => {
|
||||||
|
let target_ty =
|
||||||
|
this.read_enum_variant_arg(0, |this| Ok(this.read_ty(dcx))).unwrap();
|
||||||
|
ty::UnsizeUpcast(target_ty)
|
||||||
|
}
|
||||||
_ => panic!("bad enum variant for ty::UnsizeKind")
|
_ => panic!("bad enum variant for ty::UnsizeKind")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -857,28 +857,13 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||||||
n: uint) {
|
n: uint) {
|
||||||
debug!("walk_autoref expr={}", expr.repr(self.tcx()));
|
debug!("walk_autoref expr={}", expr.repr(self.tcx()));
|
||||||
|
|
||||||
// Match for unique trait coercions first, since we don't need the
|
|
||||||
// call to cat_expr_autoderefd.
|
|
||||||
match *autoref {
|
|
||||||
ty::AutoUnsizeUniq(ty::UnsizeVtable(..)) |
|
|
||||||
ty::AutoUnsize(ty::UnsizeVtable(..)) => {
|
|
||||||
assert!(n == 1, format!("Expected exactly 1 deref with Uniq \
|
|
||||||
AutoRefs, found: {}", n));
|
|
||||||
let cmt_unadjusted =
|
|
||||||
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
|
||||||
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
let cmt_derefd = return_if_err!(
|
|
||||||
self.mc.cat_expr_autoderefd(expr, n));
|
|
||||||
debug!("walk_adjustment: cmt_derefd={}",
|
|
||||||
cmt_derefd.repr(self.tcx()));
|
|
||||||
|
|
||||||
match *autoref {
|
match *autoref {
|
||||||
ty::AutoPtr(r, m, _) => {
|
ty::AutoPtr(r, m, _) => {
|
||||||
|
let cmt_derefd = return_if_err!(
|
||||||
|
self.mc.cat_expr_autoderefd(expr, n));
|
||||||
|
debug!("walk_adjustment: cmt_derefd={}",
|
||||||
|
cmt_derefd.repr(self.tcx()));
|
||||||
|
|
||||||
self.delegate.borrow(expr.id,
|
self.delegate.borrow(expr.id,
|
||||||
expr.span,
|
expr.span,
|
||||||
cmt_derefd,
|
cmt_derefd,
|
||||||
@@ -886,7 +871,16 @@ impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
|
|||||||
ty::BorrowKind::from_mutbl(m),
|
ty::BorrowKind::from_mutbl(m),
|
||||||
AutoRef);
|
AutoRef);
|
||||||
}
|
}
|
||||||
ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(..) => {}
|
ty::AutoUnsize(_) |
|
||||||
|
ty::AutoUnsizeUniq(_) => {
|
||||||
|
assert!(n == 1, format!("Expected exactly 1 deref with Uniq \
|
||||||
|
AutoRefs, found: {}", n));
|
||||||
|
let cmt_unadjusted =
|
||||||
|
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||||
|
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
||||||
|
}
|
||||||
|
ty::AutoUnsafe(..) => {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -314,9 +314,18 @@ pub trait Combine<'tcx> : Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn builtin_bounds(&self,
|
fn builtin_bounds(&self,
|
||||||
a: ty::BuiltinBounds,
|
a: BuiltinBounds,
|
||||||
b: ty::BuiltinBounds)
|
b: BuiltinBounds)
|
||||||
-> cres<'tcx, ty::BuiltinBounds>;
|
-> cres<'tcx, BuiltinBounds>
|
||||||
|
{
|
||||||
|
// Two sets of builtin bounds are only relatable if they are
|
||||||
|
// precisely the same (but see the coercion code).
|
||||||
|
if a != b {
|
||||||
|
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
|
||||||
|
} else {
|
||||||
|
Ok(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn trait_refs(&self,
|
fn trait_refs(&self,
|
||||||
a: &ty::TraitRef<'tcx>,
|
a: &ty::TraitRef<'tcx>,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use middle::ty::{BuiltinBounds};
|
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use middle::ty::TyVar;
|
use middle::ty::TyVar;
|
||||||
use middle::infer::combine::*;
|
use middle::infer::combine::*;
|
||||||
@@ -73,23 +72,6 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn builtin_bounds(&self,
|
|
||||||
a: BuiltinBounds,
|
|
||||||
b: BuiltinBounds)
|
|
||||||
-> cres<'tcx, BuiltinBounds>
|
|
||||||
{
|
|
||||||
// More bounds is a subtype of fewer bounds.
|
|
||||||
//
|
|
||||||
// e.g., fn:Copy() <: fn(), because the former is a function
|
|
||||||
// that only closes over copyable things, but the latter is
|
|
||||||
// any function at all.
|
|
||||||
if a != b {
|
|
||||||
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
|
|
||||||
} else {
|
|
||||||
Ok(a)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
|
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
|
||||||
debug!("{}.tys({}, {})", self.tag(),
|
debug!("{}.tys({}, {})", self.tag(),
|
||||||
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
|
a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx));
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ use super::higher_ranked::HigherRankedRelations;
|
|||||||
use super::{cres};
|
use super::{cres};
|
||||||
use super::Subtype;
|
use super::Subtype;
|
||||||
|
|
||||||
use middle::ty::{BuiltinBounds};
|
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use syntax::ast::{MutImmutable, MutMutable, Unsafety};
|
use syntax::ast::{MutImmutable, MutMutable, Unsafety};
|
||||||
use util::ppaux::mt_to_string;
|
use util::ppaux::mt_to_string;
|
||||||
@@ -94,15 +93,6 @@ impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn builtin_bounds(&self,
|
|
||||||
a: ty::BuiltinBounds,
|
|
||||||
b: ty::BuiltinBounds)
|
|
||||||
-> cres<'tcx, ty::BuiltinBounds> {
|
|
||||||
// More bounds is a subtype of fewer bounds, so
|
|
||||||
// the GLB (mutual subtype) is the union.
|
|
||||||
Ok(a.union(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
|
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
|
||||||
debug!("{}.regions({}, {})",
|
debug!("{}.regions({}, {})",
|
||||||
self.tag(),
|
self.tag(),
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ use super::lattice::*;
|
|||||||
use super::{cres};
|
use super::{cres};
|
||||||
use super::{Subtype};
|
use super::{Subtype};
|
||||||
|
|
||||||
use middle::ty::{BuiltinBounds};
|
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use syntax::ast::{MutMutable, MutImmutable, Unsafety};
|
use syntax::ast::{MutMutable, MutImmutable, Unsafety};
|
||||||
use util::ppaux::mt_to_string;
|
use util::ppaux::mt_to_string;
|
||||||
@@ -89,15 +88,6 @@ impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn builtin_bounds(&self,
|
|
||||||
a: ty::BuiltinBounds,
|
|
||||||
b: ty::BuiltinBounds)
|
|
||||||
-> cres<'tcx, ty::BuiltinBounds> {
|
|
||||||
// More bounds is a subtype of fewer bounds, so
|
|
||||||
// the LUB (mutual supertype) is the intersection.
|
|
||||||
Ok(a.intersection(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
|
fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> {
|
||||||
debug!("{}.regions({}, {})",
|
debug!("{}.regions({}, {})",
|
||||||
self.tag(),
|
self.tag(),
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ use super::higher_ranked::HigherRankedRelations;
|
|||||||
use super::{Subtype};
|
use super::{Subtype};
|
||||||
use super::type_variable::{SubtypeOf, SupertypeOf};
|
use super::type_variable::{SubtypeOf, SupertypeOf};
|
||||||
|
|
||||||
use middle::ty::{BuiltinBounds};
|
|
||||||
use middle::ty::{self, Ty};
|
use middle::ty::{self, Ty};
|
||||||
use middle::ty::TyVar;
|
use middle::ty::TyVar;
|
||||||
use util::ppaux::{Repr};
|
use util::ppaux::{Repr};
|
||||||
@@ -97,20 +96,6 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn builtin_bounds(&self, a: BuiltinBounds, b: BuiltinBounds)
|
|
||||||
-> cres<'tcx, BuiltinBounds> {
|
|
||||||
// More bounds is a subtype of fewer bounds.
|
|
||||||
//
|
|
||||||
// e.g., fn:Copy() <: fn(), because the former is a function
|
|
||||||
// that only closes over copyable things, but the latter is
|
|
||||||
// any function at all.
|
|
||||||
if a.is_superset(&b) {
|
|
||||||
Ok(a)
|
|
||||||
} else {
|
|
||||||
Err(ty::terr_builtin_bounds(expected_found(self, a, b)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
|
fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> {
|
||||||
debug!("{}.tys({}, {})", self.tag(),
|
debug!("{}.tys({}, {})", self.tag(),
|
||||||
a.repr(self.tcx()), b.repr(self.tcx()));
|
a.repr(self.tcx()), b.repr(self.tcx()));
|
||||||
|
|||||||
@@ -292,7 +292,8 @@ pub enum UnsizeKind<'tcx> {
|
|||||||
// An unsize coercion applied to the tail field of a struct.
|
// An unsize coercion applied to the tail field of a struct.
|
||||||
// The uint is the index of the type parameter which is unsized.
|
// The uint is the index of the type parameter which is unsized.
|
||||||
UnsizeStruct(Box<UnsizeKind<'tcx>>, uint),
|
UnsizeStruct(Box<UnsizeKind<'tcx>>, uint),
|
||||||
UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>)
|
UnsizeVtable(TyTrait<'tcx>, /* the self type of the trait */ Ty<'tcx>),
|
||||||
|
UnsizeUpcast(Ty<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -4631,6 +4632,9 @@ pub fn unsize_ty<'tcx>(cx: &ctxt<'tcx>,
|
|||||||
&UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
|
&UnsizeVtable(TyTrait { ref principal, ref bounds }, _) => {
|
||||||
mk_trait(cx, principal.clone(), bounds.clone())
|
mk_trait(cx, principal.clone(), bounds.clone())
|
||||||
}
|
}
|
||||||
|
&UnsizeUpcast(target_ty) => {
|
||||||
|
target_ty
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6853,6 +6857,7 @@ impl<'tcx> Repr<'tcx> for UnsizeKind<'tcx> {
|
|||||||
UnsizeLength(n) => format!("UnsizeLength({})", n),
|
UnsizeLength(n) => format!("UnsizeLength({})", n),
|
||||||
UnsizeStruct(ref k, n) => format!("UnsizeStruct({},{})", k.repr(tcx), n),
|
UnsizeStruct(ref k, n) => format!("UnsizeStruct({},{})", k.repr(tcx), n),
|
||||||
UnsizeVtable(ref a, ref b) => format!("UnsizeVtable({},{})", a.repr(tcx), b.repr(tcx)),
|
UnsizeVtable(ref a, ref b) => format!("UnsizeVtable({},{})", a.repr(tcx), b.repr(tcx)),
|
||||||
|
UnsizeUpcast(ref a) => format!("UnsizeUpcast({})", a.repr(tcx)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -480,6 +480,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::UnsizeKind<'tcx> {
|
|||||||
},
|
},
|
||||||
self_ty.fold_with(folder))
|
self_ty.fold_with(folder))
|
||||||
}
|
}
|
||||||
|
ty::UnsizeUpcast(t) => ty::UnsizeUpcast(t.fold_with(folder)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1214,17 +1214,17 @@ impl<'tcx> Repr<'tcx> for ty::ExistentialBounds<'tcx> {
|
|||||||
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
fn repr(&self, tcx: &ctxt<'tcx>) -> String {
|
||||||
let mut res = Vec::new();
|
let mut res = Vec::new();
|
||||||
|
|
||||||
let region_str = self.region_bound.user_string(tcx);
|
let region_str = self.region_bound.repr(tcx);
|
||||||
if !region_str.is_empty() {
|
if !region_str.is_empty() {
|
||||||
res.push(region_str);
|
res.push(region_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
for bound in &self.builtin_bounds {
|
for bound in &self.builtin_bounds {
|
||||||
res.push(bound.user_string(tcx));
|
res.push(bound.repr(tcx));
|
||||||
}
|
}
|
||||||
|
|
||||||
for projection_bound in &self.projection_bounds {
|
for projection_bound in &self.projection_bounds {
|
||||||
res.push(projection_bound.user_string(tcx));
|
res.push(projection_bound.repr(tcx));
|
||||||
}
|
}
|
||||||
|
|
||||||
res.connect("+")
|
res.connect("+")
|
||||||
|
|||||||
@@ -311,12 +311,16 @@ pub fn const_expr<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
|||||||
llconst = addr_of(cx, llconst, "autoref", e.id);
|
llconst = addr_of(cx, llconst, "autoref", e.id);
|
||||||
}
|
}
|
||||||
Some(box ty::AutoUnsize(ref k)) => {
|
Some(box ty::AutoUnsize(ref k)) => {
|
||||||
let info = expr::unsized_info(cx, k, e.id, ty, param_substs,
|
let info =
|
||||||
|t| ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), t));
|
expr::unsized_info(
|
||||||
|
cx, k, e.id, ty, param_substs,
|
||||||
|
|t| ty::mk_imm_rptr(cx.tcx(), cx.tcx().mk_region(ty::ReStatic), t),
|
||||||
|
|| const_get_elt(cx, llconst, &[abi::FAT_PTR_EXTRA as u32]));
|
||||||
|
|
||||||
let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span);
|
let unsized_ty = ty::unsize_ty(cx.tcx(), ty, k, e.span);
|
||||||
let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
|
let ptr_ty = type_of::in_memory_type_of(cx, unsized_ty).ptr_to();
|
||||||
let base = ptrcast(llconst, ptr_ty);
|
let base = ptrcast(llconst, ptr_ty);
|
||||||
|
|
||||||
let prev_const = cx.const_unsized().borrow_mut()
|
let prev_const = cx.const_unsized().borrow_mut()
|
||||||
.insert(base, llconst);
|
.insert(base, llconst);
|
||||||
assert!(prev_const.is_none() || prev_const == Some(llconst));
|
assert!(prev_const.is_none() || prev_const == Some(llconst));
|
||||||
|
|||||||
@@ -287,18 +287,50 @@ pub fn get_dataptr(bcx: Block, fat_ptr: ValueRef) -> ValueRef {
|
|||||||
|
|
||||||
// Retrieve the information we are losing (making dynamic) in an unsizing
|
// Retrieve the information we are losing (making dynamic) in an unsizing
|
||||||
// adjustment.
|
// adjustment.
|
||||||
|
//
|
||||||
// When making a dtor, we need to do different things depending on the
|
// When making a dtor, we need to do different things depending on the
|
||||||
// ownership of the object.. mk_ty is a function for turning `unadjusted_ty`
|
// ownership of the object.. mk_ty is a function for turning `unadjusted_ty`
|
||||||
// into a type to be destructed. If we want to end up with a Box pointer,
|
// into a type to be destructed. If we want to end up with a Box pointer,
|
||||||
// then mk_ty should make a Box pointer (T -> Box<T>), if we want a
|
// then mk_ty should make a Box pointer (T -> Box<T>), if we want a
|
||||||
// borrowed reference then it should be T -> &T.
|
// borrowed reference then it should be T -> &T.
|
||||||
pub fn unsized_info<'a, 'tcx, F>(ccx: &CrateContext<'a, 'tcx>,
|
//
|
||||||
kind: &ty::UnsizeKind<'tcx>,
|
// The `unadjusted_val` argument is a bit funny. It is intended
|
||||||
id: ast::NodeId,
|
// for use in an upcast, where the new vtable for an object will
|
||||||
unadjusted_ty: Ty<'tcx>,
|
// be drived from the old one. Hence it is a pointer to the fat
|
||||||
param_substs: &'tcx subst::Substs<'tcx>,
|
// pointer.
|
||||||
mk_ty: F) -> ValueRef where
|
pub fn unsized_info_bcx<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
|
||||||
F: FnOnce(Ty<'tcx>) -> Ty<'tcx>,
|
kind: &ty::UnsizeKind<'tcx>,
|
||||||
|
id: ast::NodeId,
|
||||||
|
unadjusted_ty: Ty<'tcx>,
|
||||||
|
unadjusted_val: ValueRef, // see above (*)
|
||||||
|
param_substs: &'tcx subst::Substs<'tcx>,
|
||||||
|
mk_ty: F)
|
||||||
|
-> ValueRef
|
||||||
|
where F: FnOnce(Ty<'tcx>) -> Ty<'tcx>
|
||||||
|
{
|
||||||
|
unsized_info(
|
||||||
|
bcx.ccx(),
|
||||||
|
kind,
|
||||||
|
id,
|
||||||
|
unadjusted_ty,
|
||||||
|
param_substs,
|
||||||
|
mk_ty,
|
||||||
|
|| Load(bcx, GEPi(bcx, unadjusted_val, &[0, abi::FAT_PTR_EXTRA])))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as `unsize_info_bcx`, but does not require a bcx -- instead it
|
||||||
|
// takes an extra closure to compute the upcast vtable.
|
||||||
|
pub fn unsized_info<'ccx, 'tcx, MK_TY, MK_UPCAST_VTABLE>(
|
||||||
|
ccx: &CrateContext<'ccx, 'tcx>,
|
||||||
|
kind: &ty::UnsizeKind<'tcx>,
|
||||||
|
id: ast::NodeId,
|
||||||
|
unadjusted_ty: Ty<'tcx>,
|
||||||
|
param_substs: &'tcx subst::Substs<'tcx>,
|
||||||
|
mk_ty: MK_TY,
|
||||||
|
mk_upcast_vtable: MK_UPCAST_VTABLE) // see notes above
|
||||||
|
-> ValueRef
|
||||||
|
where MK_TY: FnOnce(Ty<'tcx>) -> Ty<'tcx>,
|
||||||
|
MK_UPCAST_VTABLE: FnOnce() -> ValueRef,
|
||||||
{
|
{
|
||||||
// FIXME(#19596) workaround: `|t| t` causes monomorphization recursion
|
// FIXME(#19596) workaround: `|t| t` causes monomorphization recursion
|
||||||
fn identity<T>(t: T) -> T { t }
|
fn identity<T>(t: T) -> T { t }
|
||||||
@@ -312,7 +344,8 @@ pub fn unsized_info<'a, 'tcx, F>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
let ty_substs = substs.types.get_slice(subst::TypeSpace);
|
let ty_substs = substs.types.get_slice(subst::TypeSpace);
|
||||||
// The dtor for a field treats it like a value, so mk_ty
|
// The dtor for a field treats it like a value, so mk_ty
|
||||||
// should just be the identity function.
|
// should just be the identity function.
|
||||||
unsized_info(ccx, k, id, ty_substs[tp_index], param_substs, identity)
|
unsized_info(ccx, k, id, ty_substs[tp_index], param_substs,
|
||||||
|
identity, mk_upcast_vtable)
|
||||||
}
|
}
|
||||||
_ => ccx.sess().bug(&format!("UnsizeStruct with bad sty: {}",
|
_ => ccx.sess().bug(&format!("UnsizeStruct with bad sty: {}",
|
||||||
unadjusted_ty.repr(ccx.tcx())))
|
unadjusted_ty.repr(ccx.tcx())))
|
||||||
@@ -330,6 +363,12 @@ pub fn unsized_info<'a, 'tcx, F>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
consts::ptrcast(meth::get_vtable(ccx, box_ty, trait_ref, param_substs),
|
consts::ptrcast(meth::get_vtable(ccx, box_ty, trait_ref, param_substs),
|
||||||
Type::vtable_ptr(ccx))
|
Type::vtable_ptr(ccx))
|
||||||
}
|
}
|
||||||
|
&ty::UnsizeUpcast(_) => {
|
||||||
|
// For now, upcasts are limited to changes in marker
|
||||||
|
// traits, and hence never actually require an actual
|
||||||
|
// change to the vtable.
|
||||||
|
mk_upcast_vtable()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,7 +377,8 @@ pub fn unsized_info<'a, 'tcx, F>(ccx: &CrateContext<'a, 'tcx>,
|
|||||||
fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
datum: Datum<'tcx, Expr>)
|
datum: Datum<'tcx, Expr>)
|
||||||
-> DatumBlock<'blk, 'tcx, Expr> {
|
-> DatumBlock<'blk, 'tcx, Expr>
|
||||||
|
{
|
||||||
let mut bcx = bcx;
|
let mut bcx = bcx;
|
||||||
let mut datum = datum;
|
let mut datum = datum;
|
||||||
let adjustment = match bcx.tcx().adjustments.borrow().get(&expr.id).cloned() {
|
let adjustment = match bcx.tcx().adjustments.borrow().get(&expr.id).cloned() {
|
||||||
@@ -347,10 +387,10 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
}
|
}
|
||||||
Some(adj) => { adj }
|
Some(adj) => { adj }
|
||||||
};
|
};
|
||||||
debug!("unadjusted datum for expr {}: {}, adjustment={}",
|
debug!("unadjusted datum for expr {}: {} adjustment={:?}",
|
||||||
expr.repr(bcx.tcx()),
|
expr.repr(bcx.tcx()),
|
||||||
datum.to_string(bcx.ccx()),
|
datum.to_string(bcx.ccx()),
|
||||||
adjustment.repr(bcx.tcx()));
|
adjustment);
|
||||||
match adjustment {
|
match adjustment {
|
||||||
AdjustReifyFnPointer(_def_id) => {
|
AdjustReifyFnPointer(_def_id) => {
|
||||||
// FIXME(#19925) once fn item types are
|
// FIXME(#19925) once fn item types are
|
||||||
@@ -434,7 +474,6 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
debug!(" AutoUnsize");
|
debug!(" AutoUnsize");
|
||||||
unpack_datum!(bcx, unsize_expr(bcx, expr, datum, k))
|
unpack_datum!(bcx, unsize_expr(bcx, expr, datum, k))
|
||||||
}
|
}
|
||||||
|
|
||||||
&ty::AutoUnsizeUniq(ty::UnsizeLength(len)) => {
|
&ty::AutoUnsizeUniq(ty::UnsizeLength(len)) => {
|
||||||
debug!(" AutoUnsizeUniq(UnsizeLength)");
|
debug!(" AutoUnsizeUniq(UnsizeLength)");
|
||||||
unpack_datum!(bcx, unsize_unique_vec(bcx, expr, datum, len))
|
unpack_datum!(bcx, unsize_unique_vec(bcx, expr, datum, len))
|
||||||
@@ -459,16 +498,27 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span);
|
let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span);
|
||||||
debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx()));
|
debug!("unsized_ty={}", unsized_ty.repr(bcx.tcx()));
|
||||||
|
|
||||||
let info = unsized_info(bcx.ccx(), k, expr.id, datum_ty, bcx.fcx.param_substs,
|
let info = unsized_info_bcx(bcx, k, expr.id, datum_ty, datum.val, bcx.fcx.param_substs,
|
||||||
|t| ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), t));
|
|t| ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), t));
|
||||||
|
|
||||||
// Arrange cleanup
|
// Arrange cleanup
|
||||||
let lval = unpack_datum!(bcx,
|
let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id));
|
||||||
datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id));
|
|
||||||
// Compute the base pointer. This doesn't change the pointer value,
|
// Compute the base pointer. This doesn't change the pointer value,
|
||||||
// but merely its type.
|
// but merely its type.
|
||||||
let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to();
|
let ptr_ty = type_of::in_memory_type_of(bcx.ccx(), unsized_ty).ptr_to();
|
||||||
let base = PointerCast(bcx, lval.val, ptr_ty);
|
let base = if !type_is_sized(bcx.tcx(), lval.ty) {
|
||||||
|
// Normally, the source is a thin pointer and we are
|
||||||
|
// adding extra info to make a fat pointer. The exception
|
||||||
|
// is when we are upcasting an existing object fat pointer
|
||||||
|
// to use a different vtable. In that case, we want to
|
||||||
|
// load out the original data pointer so we can repackage
|
||||||
|
// it.
|
||||||
|
Load(bcx, get_dataptr(bcx, lval.val))
|
||||||
|
} else {
|
||||||
|
lval.val
|
||||||
|
};
|
||||||
|
let base = PointerCast(bcx, base, ptr_ty);
|
||||||
|
|
||||||
let llty = type_of::type_of(bcx.ccx(), unsized_ty);
|
let llty = type_of::type_of(bcx.ccx(), unsized_ty);
|
||||||
// HACK(eddyb) get around issues with lifetime intrinsics.
|
// HACK(eddyb) get around issues with lifetime intrinsics.
|
||||||
@@ -540,8 +590,8 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||||||
let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to());
|
let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to());
|
||||||
bcx = datum.store_to(bcx, base);
|
bcx = datum.store_to(bcx, base);
|
||||||
|
|
||||||
let info = unsized_info(bcx.ccx(), k, expr.id, unboxed_ty, bcx.fcx.param_substs,
|
let info = unsized_info_bcx(bcx, k, expr.id, unboxed_ty, base, bcx.fcx.param_substs,
|
||||||
|t| ty::mk_uniq(tcx, t));
|
|t| ty::mk_uniq(tcx, t));
|
||||||
Store(bcx, info, get_len(bcx, scratch.val));
|
Store(bcx, info, get_len(bcx, scratch.val));
|
||||||
|
|
||||||
DatumBlock::new(bcx, scratch.to_expr_datum())
|
DatumBlock::new(bcx, scratch.to_expr_datum())
|
||||||
@@ -1373,8 +1423,7 @@ pub fn with_field_tys<'tcx, R, F>(tcx: &ty::ctxt<'tcx>,
|
|||||||
let def = tcx.def_map.borrow()[node_id].full_def();
|
let def = tcx.def_map.borrow()[node_id].full_def();
|
||||||
match def {
|
match def {
|
||||||
def::DefVariant(enum_id, variant_id, _) => {
|
def::DefVariant(enum_id, variant_id, _) => {
|
||||||
let variant_info = ty::enum_variant_with_id(
|
let variant_info = ty::enum_variant_with_id(tcx, enum_id, variant_id);
|
||||||
tcx, enum_id, variant_id);
|
|
||||||
let fields = struct_fields(tcx, variant_id, substs);
|
let fields = struct_fields(tcx, variant_id, substs);
|
||||||
let fields = monomorphize::normalize_associated_type(tcx, &fields);
|
let fields = monomorphize::normalize_associated_type(tcx, &fields);
|
||||||
op(variant_info.disr_val, &fields[..])
|
op(variant_info.disr_val, &fields[..])
|
||||||
|
|||||||
@@ -334,15 +334,33 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||||||
let ty = ty::mk_vec(tcx, t_a, None);
|
let ty = ty::mk_vec(tcx, t_a, None);
|
||||||
Some((ty, ty::UnsizeLength(len)))
|
Some((ty, ty::UnsizeLength(len)))
|
||||||
}
|
}
|
||||||
(&ty::ty_trait(..), &ty::ty_trait(..)) => {
|
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
|
||||||
None
|
// For now, we only support upcasts from
|
||||||
|
// `Foo+Send` to `Foo` (really, any time there are
|
||||||
|
// fewer builtin bounds then before). These are
|
||||||
|
// convenient because they don't require any sort
|
||||||
|
// of change to the vtable at runtime.
|
||||||
|
if data_a.bounds.builtin_bounds != data_b.bounds.builtin_bounds &&
|
||||||
|
data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds)
|
||||||
|
{
|
||||||
|
let bounds_a1 = ty::ExistentialBounds {
|
||||||
|
region_bound: data_a.bounds.region_bound,
|
||||||
|
builtin_bounds: data_b.bounds.builtin_bounds,
|
||||||
|
projection_bounds: data_a.bounds.projection_bounds.clone(),
|
||||||
|
};
|
||||||
|
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
|
||||||
|
match self.fcx.infcx().try(|_| self.subtype(ty_a1, ty_b)) {
|
||||||
|
Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(_, &ty::ty_trait(box ty::TyTrait { ref principal, ref bounds })) => {
|
(_, &ty::ty_trait(ref data)) => {
|
||||||
// FIXME what is the purpose of `ty`?
|
Some((ty_b, ty::UnsizeVtable(ty::TyTrait { principal: data.principal.clone(),
|
||||||
let ty = ty::mk_trait(tcx, principal.clone(), bounds.clone());
|
bounds: data.bounds.clone() },
|
||||||
Some((ty, ty::UnsizeVtable(ty::TyTrait { principal: principal.clone(),
|
ty_a)))
|
||||||
bounds: bounds.clone() },
|
|
||||||
ty_a)))
|
|
||||||
}
|
}
|
||||||
(&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
|
(&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
|
||||||
if did_a == did_b => {
|
if did_a == did_b => {
|
||||||
|
|||||||
@@ -176,13 +176,13 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
|
|||||||
probe::AutoDeref(num) => {
|
probe::AutoDeref(num) => {
|
||||||
ty::AutoDerefRef {
|
ty::AutoDerefRef {
|
||||||
autoderefs: num,
|
autoderefs: num,
|
||||||
autoref: None
|
autoref: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
probe::AutoUnsizeLength(autoderefs, len) => {
|
probe::AutoUnsizeLength(autoderefs, len) => {
|
||||||
ty::AutoDerefRef {
|
ty::AutoDerefRef {
|
||||||
autoderefs: autoderefs,
|
autoderefs: autoderefs,
|
||||||
autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len)))
|
autoref: Some(ty::AutoUnsize(ty::UnsizeLength(len))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
probe::AutoRef(mutability, ref sub_adjustment) => {
|
probe::AutoRef(mutability, ref sub_adjustment) => {
|
||||||
|
|||||||
@@ -933,7 +933,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||||||
|
|
||||||
return self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment.clone()));
|
return self.pick_method(step.self_ty).map(|r| self.adjust(r, adjustment.clone()));
|
||||||
|
|
||||||
fn consider_reborrow(ty: Ty, d: uint) -> PickAdjustment {
|
fn consider_reborrow<'tcx>(ty: Ty<'tcx>, d: uint) -> PickAdjustment {
|
||||||
// Insert a `&*` or `&mut *` if this is a reference type:
|
// Insert a `&*` or `&mut *` if this is a reference type:
|
||||||
match ty.sty {
|
match ty.sty {
|
||||||
ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)),
|
ty::ty_rptr(_, ref mt) => AutoRef(mt.mutbl, box AutoDeref(d+1)),
|
||||||
@@ -978,7 +978,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||||||
fn adjust(&mut self,
|
fn adjust(&mut self,
|
||||||
result: PickResult<'tcx>,
|
result: PickResult<'tcx>,
|
||||||
adjustment: PickAdjustment)
|
adjustment: PickAdjustment)
|
||||||
-> PickResult<'tcx> {
|
-> PickResult<'tcx>
|
||||||
|
{
|
||||||
match result {
|
match result {
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
Ok(mut pick) => {
|
Ok(mut pick) => {
|
||||||
|
|||||||
@@ -1592,6 +1592,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
code: traits::ObjectCastObligation(self_ty) };
|
code: traits::ObjectCastObligation(self_ty) };
|
||||||
self.register_region_obligation(self_ty, ty_trait.bounds.region_bound, cause);
|
self.register_region_obligation(self_ty, ty_trait.bounds.region_bound, cause);
|
||||||
}
|
}
|
||||||
|
ty::UnsizeUpcast(_) => { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
src/test/compile-fail/borrowck-consume-unsize-vec.rs
Normal file
22
src/test/compile-fail/borrowck-consume-unsize-vec.rs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Check that we report an error if an upcast box is moved twice.
|
||||||
|
|
||||||
|
fn consume(_: Box<[i32]>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(b: Box<[i32;5]>) {
|
||||||
|
consume(b);
|
||||||
|
consume(b); //~ ERROR use of moved value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
24
src/test/compile-fail/borrowck-consume-upcast-box.rs
Normal file
24
src/test/compile-fail/borrowck-consume-upcast-box.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// 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 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Check that we report an error if an upcast box is moved twice.
|
||||||
|
|
||||||
|
trait Foo { fn dummy(&self); }
|
||||||
|
|
||||||
|
fn consume(_: Box<Foo>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(b: Box<Foo+Send>) {
|
||||||
|
consume(b);
|
||||||
|
consume(b); //~ ERROR use of moved value
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
}
|
||||||
@@ -12,9 +12,15 @@
|
|||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
|
|
||||||
pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> {
|
pub fn fail(x: Option<& (Iterator+Send)>) -> Option<&Iterator> {
|
||||||
// This call used to trigger an LLVM assertion because the return slot had type
|
// This call used to trigger an LLVM assertion because the return
|
||||||
// "Option<&Iterator>"* instead of "Option<&(Iterator+Send)>"*
|
// slot had type "Option<&Iterator>"* instead of
|
||||||
inner(x)
|
// "Option<&(Iterator+Send)>"* -- but this now yields a
|
||||||
|
// compilation error and I'm not sure how to create a comparable
|
||||||
|
// test. To ensure that this PARTICULAR failure doesn't occur
|
||||||
|
// again, though, I've left this test here, so if this ever starts
|
||||||
|
// to compile again, we can adjust the test appropriately (clearly
|
||||||
|
// it should never ICE...). -nmatsakis
|
||||||
|
inner(x) //~ ERROR mismatched types
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> {
|
pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> {
|
||||||
@@ -22,4 +28,4 @@ pub fn inner(x: Option<& (Iterator+Send)>) -> Option<&(Iterator+Send)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_error]
|
#[rustc_error]
|
||||||
fn main() {} //~ ERROR compilation successful
|
fn main() {}
|
||||||
|
|||||||
Reference in New Issue
Block a user