diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index dce5dbbb239d6..a8bcb97067122 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -170,5 +170,6 @@ register_diagnostics!( E0156, E0157, E0158, - E0159 + E0159, + E0160 ) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 6acd79f297607..ee964c729fca3 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -1073,9 +1073,18 @@ impl<'a> rbml_writer_helpers for Encoder<'a> { this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk))) }) } - &ty::AutoUnsafe(m) => { - this.emit_enum_variant("AutoUnsafe", 3, 1, |this| { - this.emit_enum_variant_arg(0, |this| m.encode(this)) + &ty::AutoUnsafe(m, None) => { + this.emit_enum_variant("AutoUnsafe", 3, 2, |this| { + this.emit_enum_variant_arg(0, |this| m.encode(this)); + this.emit_enum_variant_arg(1, + |this| this.emit_option(|this| this.emit_option_none())) + }) + } + &ty::AutoUnsafe(m, Some(box ref a)) => { + this.emit_enum_variant("AutoUnsafe", 3, 2, |this| { + this.emit_enum_variant_arg(0, |this| m.encode(this)); + this.emit_enum_variant_arg(1, |this| this.emit_option( + |this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))))) }) } } @@ -1635,8 +1644,16 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> { 3 => { let m: ast::Mutability = this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap(); + let a: Option> = + this.read_enum_variant_arg(1, |this| this.read_option(|this, b| { + if b { + Ok(Some(box this.read_autoref(xcx))) + } else { + Ok(None) + } + })).unwrap(); - ty::AutoUnsafe(m) + ty::AutoUnsafe(m, a) } _ => fail!("bad enum variant for ty::AutoRef") }) diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 7177516e53929..a7e49edbc8e4a 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -762,7 +762,7 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> { ty::BorrowKind::from_mutbl(m), AutoRef); } - ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(_) => {} + ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(..) => {} } } diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index f3f4a88fdee4f..f9b4c2879dc3a 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -296,8 +296,9 @@ impl Case { for (i, &ty) in self.tys.iter().enumerate() { match ty::get(ty).sty { - // &T/&mut T could either be a thin or fat pointer depending on T - ty::ty_rptr(_, ty::mt { ty, .. }) => match ty::get(ty).sty { + // &T/&mut T/*T could either be a thin or fat pointer depending on T + ty::ty_rptr(_, ty::mt { ty, .. }) + | ty::ty_ptr(ty::mt { ty, .. }) => match ty::get(ty).sty { // &[T] and &str are a pointer and length pair ty::ty_vec(_, None) | ty::ty_str => return Some(FatPointer(i, slice_elt_base)), diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index f05602bbb58c8..7c0a332ce43cd 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -566,8 +566,8 @@ pub fn compare_scalar_types<'a>( match ty::get(t).sty { ty::ty_nil => f(nil_type), - ty::ty_bool | ty::ty_ptr(_) | - ty::ty_uint(_) | ty::ty_char => f(unsigned_int), + ty::ty_bool | ty::ty_uint(_) | ty::ty_char => f(unsigned_int), + ty::ty_ptr(mt) if ty::type_is_sized(cx.tcx(), mt.ty) => f(unsigned_int), ty::ty_int(_) => f(signed_int), ty::ty_float(_) => f(floating_point), // Should never get here, because t is scalar. diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index b3798c9f84dd4..0b80c4f0b7a73 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -243,7 +243,7 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef } Some(ref autoref) => { match *autoref { - ty::AutoUnsafe(_) | + ty::AutoUnsafe(_, None) | ty::AutoPtr(ty::ReStatic, _, None) => { // Don't copy data to do a deref+ref // (i.e., skip the last auto-deref). diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 72f99a3802dcb..ce4c5c9de1688 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -254,11 +254,7 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>, let mut datum = datum; let datum = match autoref { - &AutoUnsafe(..) => { - debug!(" AutoUnsafe"); - unpack_datum!(bcx, ref_ptr(bcx, expr, datum)) - } - &AutoPtr(_, _, ref a) => { + &AutoPtr(_, _, ref a) | &AutoUnsafe(_, ref a) => { debug!(" AutoPtr"); match a { &Some(box ref a) => datum = unpack_datum!(bcx, @@ -1847,8 +1843,7 @@ pub fn cast_type_kind(tcx: &ty::ctxt, t: ty::t) -> cast_kind { match ty::get(t).sty { ty::ty_char => cast_integral, ty::ty_float(..) => cast_float, - ty::ty_ptr(..) => cast_pointer, - ty::ty_rptr(_, mt) => { + ty::ty_rptr(_, mt) | ty::ty_ptr(mt) => { if ty::type_is_sized(tcx, mt.ty) { cast_pointer } else { diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 11c641f2d75a2..a49dc1b915028 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -154,7 +154,7 @@ impl<'a, 'b> Reflector<'a, 'b> { // Unfortunately we can't do anything here because at runtime we // pass around the value by pointer (*u8). But unsized pointers are // fat and so we can't just cast them to *u8 and back. So we have - // to work with the pointer directly (see ty_rptr/ty_uniq). + // to work with the pointer directly (see ty_ptr/ty_rptr/ty_uniq). fail!("Can't reflect unsized type") } // FIXME(15049) Reflection for unsized structs. @@ -177,8 +177,24 @@ impl<'a, 'b> Reflector<'a, 'b> { self.visit("box", extra.as_slice()) } ty::ty_ptr(ref mt) => { - let extra = self.c_mt(mt); - self.visit("ptr", extra.as_slice()) + match ty::get(mt.ty).sty { + ty::ty_vec(ty, None) => { + let extra = self.c_mt(&ty::mt{ty: ty, mutbl: mt.mutbl}); + self.visit("evec_slice", extra.as_slice()) + } + ty::ty_str => self.visit("estr_slice", &[]), + ty::ty_trait(..) => { + let extra = [ + self.c_slice(token::intern_and_get_ident( + ty_to_string(tcx, t).as_slice())) + ]; + self.visit("trait", extra); + } + _ => { + let extra = self.c_mt(mt); + self.visit("ptr", extra.as_slice()) + } + } } ty::ty_uniq(typ) => { match ty::get(typ).sty { diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 83c792ecf8782..ab7e71c41d368 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -174,9 +174,8 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_uint(t) => Type::uint_from_ty(cx, t), ty::ty_float(t) => Type::float_from_ty(cx, t), - ty::ty_box(..) | - ty::ty_ptr(..) => Type::i8p(cx), - ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => { + ty::ty_box(..) => Type::i8p(cx), + ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => { if ty::type_is_sized(cx.tcx(), ty) { Type::i8p(cx) } else { @@ -303,9 +302,8 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type { ty::ty_box(typ) => { Type::at_box(cx, type_of(cx, typ)).ptr_to() } - ty::ty_ptr(ref mt) => type_of(cx, mt.ty).ptr_to(), - ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => { + ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => { match ty::get(ty).sty { ty::ty_str => { // This means we get a nicer name in the output (str is always diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 557b7b70947f1..5198a96291286 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -298,7 +298,8 @@ pub enum AutoRef { /// Convert from T to *T /// Value to thin pointer - AutoUnsafe(ast::Mutability), + /// The second field allows us to wrap other AutoRef adjustments. + AutoUnsafe(ast::Mutability, Option>), } // Ugly little helper function. The first bool in the returned tuple is true if @@ -326,6 +327,7 @@ fn autoref_object_region(autoref: &AutoRef) -> (bool, bool, Option) { (b, u, Some(adj_r)) } } + &AutoUnsafe(_, Some(box ref autoref)) => autoref_object_region(autoref), _ => (false, false, None) } } @@ -380,6 +382,12 @@ pub fn type_of_adjust(cx: &ctxt, adj: &AutoAdjustment) -> Option { None => None } } + &AutoUnsafe(m, Some(box ref autoref)) => { + match type_of_autoref(cx, autoref) { + Some(t) => Some(mk_ptr(cx, mt {mutbl: m, ty: t})), + None => None + } + } _ => None } } @@ -1898,7 +1906,7 @@ pub fn type_is_self(ty: t) -> bool { fn type_is_slice(ty: t) -> bool { match get(ty).sty { - ty_rptr(_, mt) => match get(mt.ty).sty { + ty_ptr(mt) | ty_rptr(_, mt) => match get(mt.ty).sty { ty_vec(_, None) | ty_str => true, _ => false, }, @@ -1996,7 +2004,8 @@ pub fn type_is_unique(ty: t) -> bool { pub fn type_is_fat_ptr(cx: &ctxt, ty: t) -> bool { match get(ty).sty { - ty_rptr(_, mt{ty, ..}) | ty_uniq(ty) if !type_is_sized(cx, ty) => true, + ty_ptr(mt{ty, ..}) | ty_rptr(_, mt{ty, ..}) + | ty_uniq(ty) if !type_is_sized(cx, ty) => true, _ => false, } } @@ -2896,7 +2905,7 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability { pub fn type_is_trait(ty: t) -> bool { match get(ty).sty { - ty_uniq(ty) | ty_rptr(_, mt { ty, ..}) => match get(ty).sty { + ty_uniq(ty) | ty_rptr(_, mt { ty, ..}) | ty_ptr(mt { ty, ..}) => match get(ty).sty { ty_trait(..) => true, _ => false }, @@ -3392,8 +3401,12 @@ pub fn adjust_ty(cx: &ctxt, }) } - AutoUnsafe(m) => { - mk_ptr(cx, mt {ty: ty, mutbl: m}) + AutoUnsafe(m, ref a) => { + let adjusted_ty = match a { + &Some(box ref a) => adjust_for_autoref(cx, span, ty, a), + &None => ty + }; + mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m}) } AutoUnsize(ref k) => unsize_ty(cx, ty, k, span), @@ -3444,7 +3457,8 @@ impl AutoRef { ty::AutoPtr(r, m, Some(ref a)) => ty::AutoPtr(f(r), m, Some(box a.map_region(f))), ty::AutoUnsize(ref k) => ty::AutoUnsize(k.clone()), ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.clone()), - ty::AutoUnsafe(m) => ty::AutoUnsafe(m), + ty::AutoUnsafe(m, None) => ty::AutoUnsafe(m, None), + ty::AutoUnsafe(m, Some(ref a)) => ty::AutoUnsafe(m, Some(box a.map_region(f))), } } } diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 435c591f881bb..07c8573ef853b 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -466,7 +466,10 @@ pub fn super_fold_autoref(this: &mut T, ty::AutoPtr(r, m, Some(ref a)) => { ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, &**a))) } - ty::AutoUnsafe(m) => ty::AutoUnsafe(m), + ty::AutoUnsafe(m, None) => ty::AutoUnsafe(m, None), + ty::AutoUnsafe(m, Some(ref a)) => { + ty::AutoUnsafe(m, Some(box super_fold_autoref(this, &**a))) + } ty::AutoUnsize(ref k) => ty::AutoUnsize(k.fold_with(this)), ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.fold_with(this)), } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 93a14428f8f70..0ce4dd9602591 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -3650,7 +3650,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt, ast::ExprAddrOf(mutbl, ref oprnd) => { let expected = expected.only_has_type(); let hint = expected.map(fcx, |sty| { - match *sty { ty::ty_rptr(_, ref mt) => ExpectHasType(mt.ty), + match *sty { ty::ty_rptr(_, ref mt) | ty::ty_ptr(ref mt) => ExpectHasType(mt.ty), _ => NoExpectation } }); let lvalue_pref = match mutbl { diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index db9d52814b6e1..16ecaa9714ec7 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -1363,7 +1363,7 @@ fn link_autoref(rcx: &Rcx, ty::BorrowKind::from_mutbl(m), expr_cmt); } - ty::AutoUnsafe(_) | ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {} + ty::AutoUnsafe(..) | ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {} } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 2d4022a2eaa52..31621c72f6595 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -630,9 +630,13 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { let cx = fcx.ccx; let check_object_cast = |src_ty: ty::t, target_ty: ty::t| { + debug!("check_object_cast {} to {}", + fcx.infcx().ty_to_string(src_ty), + fcx.infcx().ty_to_string(target_ty)); // Check that a cast is of correct types. match (&ty::get(target_ty).sty, &ty::get(src_ty).sty) { (&ty::ty_rptr(_, ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt)) + | (&ty::ty_ptr(ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt)) if !mutability_allowed(mt.mutbl, mutbl) => { match ty::get(ty).sty { ty::ty_trait(..) => { @@ -641,7 +645,9 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { _ => {} } } - (&ty::ty_uniq(..), &ty::ty_uniq(..) ) => {} + (&ty::ty_uniq(..), &ty::ty_uniq(..) ) + | (&ty::ty_ptr(..), &ty::ty_ptr(..) ) + | (&ty::ty_ptr(..), &ty::ty_rptr(..)) => {} (&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => { infer::mk_subr(fcx.infcx(), infer::RelateObjectBound(ex.span), @@ -669,6 +675,16 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) { _ => {} } } + (&ty::ty_ptr(ty::mt{ty, ..}), _) => { + match ty::get(ty).sty { + ty::ty_trait(..) => { + span_err!(fcx.ccx.tcx.sess, ex.span, E0160, + "can only cast an *-pointer or &-pointer to an *-object, not a {}", + ty::ty_sort_string(fcx.tcx(), src_ty)); + } + _ => {} + } + } _ => {} } }; @@ -880,7 +896,8 @@ fn trait_cast_types(fcx: &FnCtxt, match autoref { &ty::AutoUnsize(ref k) | &ty::AutoUnsizeUniq(ref k) => trait_cast_types_unsize(fcx, k, src_ty, sp), - &ty::AutoPtr(_, _, Some(box ref autoref)) => { + &ty::AutoPtr(_, _, Some(box ref autoref)) + | &ty::AutoUnsafe(_, Some(box ref autoref))=> { trait_cast_types_autoref(fcx, autoref, src_ty, sp) } _ => None @@ -891,7 +908,7 @@ fn trait_cast_types(fcx: &FnCtxt, &ty::AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), autoderefs}) => { let mut derefed_type = src_ty; for _ in range(0, autoderefs) { - derefed_type = ty::deref(derefed_type, false).unwrap().ty; + derefed_type = ty::deref(derefed_type, true).unwrap().ty; derefed_type = structurally_resolved_type(fcx, sp, derefed_type) } trait_cast_types_autoref(fcx, autoref, derefed_type, sp) diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index a6fa9d84600bf..87b6213694a29 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -157,7 +157,8 @@ fn get_base_type_def_id(inference_context: &InferCtxt, ty_unboxed_closure(def_id, _) => { Some(def_id) } - ty_rptr(_, ty::mt {ty, ..}) | ty_uniq(ty) => match ty::get(ty).sty { + ty_ptr(ty::mt {ty, ..}) | ty_rptr(_, ty::mt {ty, ..}) | ty_uniq(ty) + => match ty::get(ty).sty { ty_trait(box ty::TyTrait { def_id, .. }) => { Some(def_id) } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index e7bc06d4972e4..c22baa1d9e5d3 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -1401,7 +1401,7 @@ fn check_method_self_type( ast::SelfExplicit(ref ast_type, _) => { let typ = crate_context.to_ty(rs, &**ast_type); let base_type = match ty::get(typ).sty { - ty::ty_rptr(_, tm) => tm.ty, + ty::ty_ptr(tm) | ty::ty_rptr(_, tm) => tm.ty, ty::ty_uniq(typ) => typ, _ => typ, }; diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 9013b468d3f89..acfe588c680ad 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -65,7 +65,7 @@ we may want to adjust precisely when coercions occur. */ use middle::subst; -use middle::ty::{AutoPtr, AutoDerefRef, AutoUnsize}; +use middle::ty::{AutoPtr, AutoDerefRef, AutoUnsize, AutoUnsafe}; use middle::ty::{mt}; use middle::ty; use middle::typeck::infer::{CoerceResult, resolve_type, Coercion}; @@ -100,7 +100,7 @@ impl<'f> Coerce<'f> { // to `&[T]`. Doing it all at once makes the target code a bit more // efficient and spares us from having to handle multiple coercions. match ty::get(b).sty { - ty::ty_rptr(_, mt_b) => { + ty::ty_ptr(mt_b) | ty::ty_rptr(_, mt_b) => { match ty::get(mt_b.ty).sty { ty::ty_vec(_, None) => { let unsize_and_ref = self.unpack_actual_value(a, |sty_a| { @@ -129,6 +129,33 @@ impl<'f> Coerce<'f> { // Note: does not attempt to resolve type variables we encounter. // See above for details. match ty::get(b).sty { + ty::ty_ptr(mt_b) => { + match ty::get(mt_b.ty).sty { + ty::ty_str => { + return self.unpack_actual_value(a, |sty_a| { + self.coerce_unsafe_ptr(a, sty_a, b, ast::MutImmutable) + }); + } + + ty::ty_trait(..) => { + let result = self.unpack_actual_value(a, |sty_a| { + self.coerce_unsafe_object(a, sty_a, b, mt_b.mutbl) + }); + + match result { + Ok(t) => return Ok(t), + Err(..) => {} + } + } + + _ => { + return self.unpack_actual_value(a, |sty_a| { + self.coerce_unsafe_ptr(a, sty_a, b, mt_b.mutbl) + }); + } + }; + } + ty::ty_rptr(_, mt_b) => { match ty::get(mt_b.ty).sty { ty::ty_str => { @@ -165,12 +192,6 @@ impl<'f> Coerce<'f> { }); } - ty::ty_ptr(mt_b) => { - return self.unpack_actual_value(a, |sty_a| { - self.coerce_unsafe_ptr(a, sty_a, b, mt_b) - }); - } - _ => {} } @@ -329,6 +350,26 @@ impl<'f> Coerce<'f> { } }) } + (&ty::ty_ptr(ty::mt{ty: t_a, ..}), &ty::ty_ptr(mt_b)) + | (&ty::ty_rptr(_, ty::mt{ty: t_a, ..}), &ty::ty_ptr(mt_b)) => { + self.unpack_actual_value(t_a, |sty_a| { + match self.unsize_ty(sty_a, mt_b.ty) { + Some((ty, kind)) => { + let ty = ty::mk_ptr(self.get_ref().infcx.tcx, + ty::mt{ty: ty, mutbl: mt_b.mutbl}); + try!(self.get_ref().infcx.try(|| sub.tys(ty, b))); + debug!("Success, coerced with AutoDerefRef(1, \ + AutoPtr(AutoUnsize({:?})))", kind); + Ok(Some(AutoDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(ty::AutoUnsafe(mt_b.mutbl, + Some(box AutoUnsize(kind)))) + }))) + } + _ => Err(ty::terr_mismatch) + } + }) + } (&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => { self.unpack_actual_value(t_a, |sty_a| { match self.unsize_ty(sty_a, t_b) { @@ -357,7 +398,7 @@ impl<'f> Coerce<'f> { sty_a: &ty::sty, ty_b: ty::t) -> Option<(ty::t, ty::UnsizeKind)> { - debug!("unsize_ty(sty_a={:?}", sty_a); + debug!("unsize_ty(sty_a={:?}, ty_b={})", sty_a, ty_b.repr(self.get_ref().infcx.tcx)); let tcx = self.get_ref().infcx.tcx; @@ -430,15 +471,15 @@ impl<'f> Coerce<'f> { b: ty::t, b_mutbl: ast::Mutability) -> CoerceResult { + let tcx = self.get_ref().infcx.tcx; + debug!("coerce_borrowed_object(a={}, sty_a={:?}, b={})", - a.repr(self.get_ref().infcx.tcx), sty_a, - b.repr(self.get_ref().infcx.tcx)); + a.repr(tcx), sty_a, + b.repr(tcx)); - let tcx = self.get_ref().infcx.tcx; let coercion = Coercion(self.get_ref().trace.clone()); - let r_a = self.get_ref().infcx.next_region_var(coercion); - let a_borrowed = match *sty_a { + match *sty_a { ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty { ty::ty_trait(box ty::TyTrait { def_id, @@ -447,22 +488,63 @@ impl<'f> Coerce<'f> { .. }) => { let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds); - ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr }) + let r_a = self.get_ref().infcx.next_region_var(coercion); + let a_borrowed = ty::mk_rptr(tcx, r_a, ty::mt{ mutbl: b_mutbl, ty: tr }); + + try!(self.subtype(a_borrowed, b)); + Ok(Some(AutoDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(AutoPtr(r_a, b_mutbl, None)) + }))) } _ => { - return self.subtype(a, b); + self.subtype(a, b) } }, _ => { - return self.subtype(a, b); + self.subtype(a, b) } - }; + } + } - try!(self.subtype(a_borrowed, b)); - Ok(Some(AutoDerefRef(AutoDerefRef { - autoderefs: 1, - autoref: Some(AutoPtr(r_a, b_mutbl, None)) - }))) + fn coerce_unsafe_object(&self, + a: ty::t, + sty_a: &ty::sty, + b: ty::t, + b_mutbl: ast::Mutability) -> CoerceResult + { + let tcx = self.get_ref().infcx.tcx; + + debug!("coerce_unsafe_object(a={}, sty_a={:?}, b={})", + a.repr(tcx), sty_a, + b.repr(tcx)); + + match *sty_a { + ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | + ty::ty_ptr(ty::mt{ty, ..}) => match ty::get(ty).sty { + ty::ty_trait(box ty::TyTrait { + def_id, + ref substs, + bounds, + .. + }) => { + let tr = ty::mk_trait(tcx, def_id, substs.clone(), bounds); + let a_raw = ty::mk_ptr(tcx, ty::mt{ mutbl: b_mutbl, ty: tr }); + + try!(self.subtype(a_raw, b)); + Ok(Some(AutoDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(AutoUnsafe(b_mutbl, None)) + }))) + } + _ => { + self.subtype(a, b) + } + }, + _ => { + self.subtype(a, b) + } + } } pub fn coerce_borrowed_fn(&self, @@ -521,7 +603,7 @@ impl<'f> Coerce<'f> { a: ty::t, sty_a: &ty::sty, b: ty::t, - mt_b: ty::mt) + mutbl_b: ast::Mutability) -> CoerceResult { debug!("coerce_unsafe_ptr(a={}, sty_a={:?}, b={})", a.repr(self.get_ref().infcx.tcx), sty_a, @@ -534,16 +616,18 @@ impl<'f> Coerce<'f> { } }; - // check that the types which they point at are compatible + // Check that the types which they point at are compatible. + // Note that we don't adjust the mutability here. We cannot change + // the mutability and the kind of pointer in a single coercion. let a_unsafe = ty::mk_ptr(self.get_ref().infcx.tcx, mt_a); try!(self.subtype(a_unsafe, b)); - // although references and unsafe ptrs have the same + // Although references and unsafe ptrs have the same // representation, we still register an AutoDerefRef so that - // regionck knows that the region for `a` must be valid here + // regionck knows that the region for `a` must be valid here. Ok(Some(AutoDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(ty::AutoUnsafe(mt_b.mutbl)) + autoref: Some(ty::AutoUnsafe(mutbl_b, None)) }))) } } diff --git a/src/test/compile-fail/dst-bad-coercions.rs b/src/test/compile-fail/dst-bad-coercions.rs new file mode 100644 index 0000000000000..b1bea2cb57fc2 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coercions.rs @@ -0,0 +1,28 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S; +trait T {} +impl T for S {} + +pub fn main() { + let x: *const S = &S; + let y: &S = x; //~ ERROR mismatched types: expected `&S`, found `*const S` (expected &-ptr + let y: &T = x; //~ ERROR mismatched types: expected `&T`, found `*const S` (expected &-ptr + + let x: *mut S = &mut S; + let y: &S = x; //~ ERROR mismatched types: expected `&S`, found `*mut S` (expected &-ptr + let y: &T = x; //~ ERROR mismatched types: expected `&T`, found `*mut S` (expected &-ptr + + let x: &mut T = &S; //~ ERROR types differ in mutability + let x: *mut T = &S; //~ ERROR types differ in mutability + let x: *mut S = &S; + //~^ ERROR mismatched types: expected `*mut S`, found `&S` (values differ in mutability) +} \ No newline at end of file diff --git a/src/test/run-pass/dst-coercions.rs b/src/test/run-pass/dst-coercions.rs new file mode 100644 index 0000000000000..1b3776c86a2c0 --- /dev/null +++ b/src/test/run-pass/dst-coercions.rs @@ -0,0 +1,28 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S; +trait T {} +impl T for S {} + +pub fn main() { + let x: &T = &S; + let x: *const T = &S; + + let x: *const S = &S; + + let x: &mut T = &mut S; + let x: *mut T = &mut S; + + let x: *mut S = &mut S; + + let x: &T = &mut S; + let x: *const T = &mut S; +} \ No newline at end of file diff --git a/src/test/run-pass/dst-raw.rs b/src/test/run-pass/dst-raw.rs new file mode 100644 index 0000000000000..21c29f1637e4c --- /dev/null +++ b/src/test/run-pass/dst-raw.rs @@ -0,0 +1,91 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test DST raw pointers + +trait Trait { + fn foo(&self) -> int; +} + +struct A { + f: int +} +impl Trait for A { + fn foo(&self) -> int { + self.f + } +} + +pub struct Foo { + f: T +} + +pub fn main() { + // raw trait object + let x = A { f: 42 }; + let y: *const A = &x; + let z: *const Trait = y; + let r = unsafe { + (&*z).foo() + }; + assert!(r == 42); + + // raw DST struct + let p = Foo {f: A { f: 42 }}; + let q: *const Foo = &p; + let o: *const Foo = q; + let r = unsafe { + (&*o).f.foo() + }; + assert!(r == 42); + + // raw slice + let a: *const [_] = &[1i, 2, 3]; + unsafe { + let b = (*a)[2]; + assert!(b == 3); + } + + // raw DST struct with slice + let c: *const Foo<[_]> = &Foo {f: [1i, 2, 3]}; + unsafe { + let b = (&*c).f[0]; + assert!(b == 1); + } + + // all of the above with *mut + let mut x = A { f: 42 }; + let y: *mut A = &mut x; + let z: *mut Trait = y; + let r = unsafe { + (&*z).foo() + }; + assert!(r == 42); + + let mut p = Foo {f: A { f: 42 }}; + let q: *mut Foo = &mut p; + let o: *mut Foo = q; + let r = unsafe { + (&*o).f.foo() + }; + assert!(r == 42); + + let a: *mut [_] = &mut [1i, 2, 3]; + unsafe { + let b = (*a)[2]; + assert!(b == 3); + } + + let c: *mut Foo<[_]> = &mut Foo {f: [1i, 2, 3]}; + unsafe { + let b = (&*c).f[0]; + assert!(b == 1); + } +} \ No newline at end of file