]> git.lizzy.rs Git - rust.git/commitdiff
DST raw pointers - *-pointers are fat pointers
authorNick Cameron <ncameron@mozilla.com>
Wed, 27 Aug 2014 05:07:28 +0000 (17:07 +1200)
committerNick Cameron <ncameron@mozilla.com>
Mon, 1 Sep 2014 22:05:00 +0000 (10:05 +1200)
20 files changed:
src/librustc/diagnostics.rs
src/librustc/middle/astencode.rs
src/librustc/middle/expr_use_visitor.rs
src/librustc/middle/trans/adt.rs
src/librustc/middle/trans/base.rs
src/librustc/middle/trans/consts.rs
src/librustc/middle/trans/expr.rs
src/librustc/middle/trans/reflect.rs
src/librustc/middle/trans/type_of.rs
src/librustc/middle/ty.rs
src/librustc/middle/ty_fold.rs
src/librustc/middle/typeck/check/mod.rs
src/librustc/middle/typeck/check/regionck.rs
src/librustc/middle/typeck/check/vtable.rs
src/librustc/middle/typeck/coherence.rs
src/librustc/middle/typeck/collect.rs
src/librustc/middle/typeck/infer/coercion.rs
src/test/compile-fail/dst-bad-coercions.rs [new file with mode: 0644]
src/test/run-pass/dst-coercions.rs [new file with mode: 0644]
src/test/run-pass/dst-raw.rs [new file with mode: 0644]

index dce5dbbb239d68e1d9586bc8d0269affde63cf17..a8bcb97067122baad16374474023560f3f06389b 100644 (file)
     E0156,
     E0157,
     E0158,
-    E0159
+    E0159,
+    E0160
 )
index 6acd79f29760738360aa1d3250f141e5740a19e3..ee964c729fca35e7acf06413405fe9c6d0a15438 100644 (file)
@@ -1073,9 +1073,18 @@ fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef) {
                         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 @@ fn read_autoref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoRef {
                     3 => {
                         let m: ast::Mutability =
                             this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
+                        let a: Option<Box<ty::AutoRef>> =
+                            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")
                 })
index 7177516e539298dd03466d5827ab07d0db1c4d85..a7e49edbc8e4a5972a9f6cb5c7989975abd7855d 100644 (file)
@@ -762,7 +762,7 @@ fn walk_autoref(&mut self,
                                      ty::BorrowKind::from_mutbl(m),
                                      AutoRef);
             }
-            ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(_) => {}
+            ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(..) => {}
         }
     }
 
index f3f4a88fdee4fa9c32106499091758c91a3d42f1..f9b4c2879dc3ae07a4b893886f8d52ed7096fefa 100644 (file)
@@ -296,8 +296,9 @@ fn find_ptr(&self) -> Option<PointerField> {
 
         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)),
 
index f05602bbb58c830fabc42bc4cf9b418a06781887..7c0a332ce43cd2deb0eb9ea3f776afb3fd2ec0be 100644 (file)
@@ -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.
index b3798c9f84dd41ab6d2625f1b0864302e95b33dc..0b80c4f0b7a73e14d18a33d54a008c04638c8341 100644 (file)
@@ -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).
index 72f99a3802dcbc2ff62015e24ac3ff0732dc411f..ce4c5c9de1688e2adda2fb0674ec6118e58e8632 100644 (file)
@@ -254,11 +254,7 @@ fn apply_autoref<'a>(autoref: &ty::AutoRef,
         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 {
index 11c641f2d75a245b8eda0762145972cf24850405..a49dc1b915028552db0bfb668f4d008238575d14 100644 (file)
@@ -154,7 +154,7 @@ pub fn visit_ty(&mut self, t: ty::t) {
               // 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 @@ pub fn visit_ty(&mut self, t: ty::t) {
               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 {
index 83c792ecf8782b43c4ad0ad89f7d4d63812dbbd1..ab7e71c41d3685c9db530c9cd18eb67138082d86 100644 (file)
@@ -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 @@ fn type_of_unsize_info(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
index 557b7b70947f1729d6bf2198ba99ae9420eb42d2..5198a96291286807e6bb873cfa4607ac473bcefd 100644 (file)
@@ -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<Box<AutoRef>>),
 }
 
 // Ugly little helper function. The first bool in the returned tuple is true if
@@ -326,6 +327,7 @@ fn unsize_kind_is_object(k: &UnsizeKind) -> bool {
                 (b, u, Some(adj_r))
             }
         }
+        &AutoUnsafe(_, Some(box ref autoref)) => autoref_object_region(autoref),
         _ => (false, false, None)
     }
 }
@@ -380,6 +382,12 @@ fn type_of_autoref(cx: &ctxt, autoref: &AutoRef) -> Option<t> {
                     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 @@ fn type_structurally_recursive(cx: &ctxt, sp: Span, seen: &mut Vec<DefId>,
 
 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 @@ fn adjust_for_autoref(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 @@ pub fn map_region(&self, f: |Region| -> Region) -> 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))),
         }
     }
 }
index 435c591f881bbda26713d1f1cfd9c71fe8a64209..07c8573ef853ba8b8c5129dc572145baaf166d9a 100644 (file)
@@ -466,7 +466,10 @@ pub fn super_fold_autoref<T:TypeFolder>(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)),
     }
index 93a14428f8f70dbdb29dc072aa79c9349167db14..0ce4dd96025912244d89c6539fa96810e84fe673 100644 (file)
@@ -3650,7 +3650,7 @@ fn check_struct_fields_on_error(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 {
index db9d52814b6e169462c32363af321eed1aefaac3..16ecaa9714ec73a0b3102b0c1b0e27d7a77312ab 100644 (file)
@@ -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(_) => {}
     }
 }
 
index 2d4022a2eaa52a2409172e9b175ca9fe9b82c7c3..31621c72f6595099a44e10520b7de2863ec526e4 100644 (file)
@@ -630,9 +630,13 @@ fn mutability_allowed(a_mutbl: ast::Mutability,
 
     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 @@ fn mutability_allowed(a_mutbl: ast::Mutability,
                   _ => {}
               }
           }
-          (&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 @@ fn mutability_allowed(a_mutbl: ast::Mutability,
                   _ => {}
               }
           }
+          (&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_unsize(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_unsize(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)
index a6fa9d84600bf6d5fb8fea5c95f6b16a79b64a4e..87b6213694a290f3c4c2a5cc5f412bd521305399 100644 (file)
@@ -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)
                     }
index e7bc06d4972e48e05c507ce413e6b65c671f2280..c22baa1d9e5d3aa0466333129a95ccdf510048f4 100644 (file)
@@ -1401,7 +1401,7 @@ fn check_method_self_type<RS:RegionScope>(
         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,
             };
index 9013b468d3f89742e8bc0485b151aad91ab0af01..acfe588c680adcafaba33edeed25dfcafa402712 100644 (file)
@@ -65,7 +65,7 @@ fn foo<A>(a: A, b: A) { ... }
 */
 
 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 @@ pub fn tys(&self, a: ty::t, b: ty::t) -> CoerceResult {
         // 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 @@ pub fn tys(&self, a: ty::t, b: ty::t) -> CoerceResult {
         // 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 @@ pub fn tys(&self, a: ty::t, b: ty::t) -> CoerceResult {
                 });
             }
 
-            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 @@ fn coerce_unsized(&self,
                     }
                 })
             }
+            (&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 @@ fn unsize_ty(&self,
                  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 @@ fn coerce_borrowed_object(&self,
                               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 @@ fn coerce_borrowed_object(&self,
                         ..
                     }) => {
                     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 @@ pub fn coerce_unsafe_ptr(&self,
                              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 @@ pub fn coerce_unsafe_ptr(&self,
             }
         };
 
-        // 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 (file)
index 0000000..b1bea2c
--- /dev/null
@@ -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 <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.
+
+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 (file)
index 0000000..1b3776c
--- /dev/null
@@ -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 <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.
+
+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 (file)
index 0000000..21c29f1
--- /dev/null
@@ -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 <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.
+
+// 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<Sized? T> {
+    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<A> = &p;
+    let o: *const Foo<Trait> = 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<A> = &mut p;
+    let o: *mut Foo<Trait> = 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