]> git.lizzy.rs Git - rust.git/commitdiff
require the non-last elements of a tuple to be Sized
authorAriel Ben-Yehuda <ariel.byd@gmail.com>
Thu, 21 Apr 2016 22:46:23 +0000 (01:46 +0300)
committerAriel Ben-Yehuda <ariel.byd@gmail.com>
Tue, 3 May 2016 15:30:10 +0000 (18:30 +0300)
This requirement appears to be missing from RFC1214, but is clearly
necessary for translation. The last field of a tuple/enum remains in
a state of limbo, compiling but causing an ICE when it is used - we
should eventually fix that somehow.

this is a [breaking-change] - a soundness fix - and requires a
crater run.

src/libcore/num/bignum.rs
src/librustc/traits/error_reporting.rs
src/librustc/traits/mod.rs
src/librustc/traits/select.rs
src/librustc/ty/mod.rs
src/librustc/ty/wf.rs
src/test/compile-fail/unsized3.rs
src/test/compile-fail/unsized6.rs

index 66c6deb361564305d964616cf078a29865549833..a881b539cedebf0ba5dbb4b2c6342f458c6c89ba 100644 (file)
@@ -33,7 +33,7 @@
 use intrinsics;
 
 /// Arithmetic operations required by bignums.
-pub trait FullOps {
+pub trait FullOps: Sized {
     /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
     /// where `W` is the number of bits in `Self`.
     fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self);
index 531a4fbf8beba07aa009ffa2dc04930a08c20647..d02dfcd9ea7999d549933db40bf21ecb747a7692 100644 (file)
@@ -764,6 +764,11 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
         ObligationCauseCode::SliceOrArrayElem => {
             err.note("slice and array elements must have `Sized` type");
         }
+        ObligationCauseCode::TupleElem => {
+            err.fileline_note(
+                cause_span,
+                "tuple elements must have `Sized` type");
+        }
         ObligationCauseCode::ProjectionWf(data) => {
             err.note(&format!("required so that the projection `{}` is well-formed",
                               data));
index a160465e2e815694dafdac08095c7fa0c699a7aa..5921cdeab78677323a10071081d7b41246886410 100644 (file)
@@ -106,9 +106,12 @@ pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from span.
     MiscObligation,
 
-    /// This is the trait reference from the given projection
+    /// A slice or array is WF only if `T: Sized`
     SliceOrArrayElem,
 
+    /// A tuple is WF only if its middle elements are Sized
+    TupleElem,
+
     /// This is the trait reference from the given projection
     ProjectionWf(ty::ProjectionTy<'tcx>),
 
index 3a208aba6d83cfc0063f91521aeb53d7a93da1c1..08a996c142d480e8182f678705a43757eb28582d 100644 (file)
@@ -1652,7 +1652,7 @@ fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
             ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
             ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) |
             ty::TyChar | ty::TyBox(_) | ty::TyRef(..) |
-            ty::TyArray(..) | ty::TyTuple(..) | ty::TyClosure(..) |
+            ty::TyArray(..) | ty::TyClosure(..) |
             ty::TyError => {
                 // safe for everything
                 Where(ty::Binder(Vec::new()))
@@ -1660,6 +1660,13 @@ fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
 
             ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never,
 
+            ty::TyTuple(ref tys) => {
+                Where(ty::Binder(match tys.last() {
+                    Some(ty) => vec![ty],
+                    _ => vec![]
+                }))
+            }
+
             ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
                 let sized_crit = def.sized_constraint(self.tcx());
                 // (*) binder moved here
index 179c83873762d659081d0bda5406cea0d486f0b6..b4156fde6a3bc592400b8820594fac12ef498ab4 100644 (file)
@@ -1761,8 +1761,8 @@ fn sized_constraint_for_tys<TYS>(
         let tys : Vec<_> = tys.into_iter()
             .map(|ty| self.sized_constraint_for_ty(tcx, stack, ty))
             .flat_map(|ty| match ty.sty {
-                ty::TyTuple(ref tys) => tys.clone(),
-                _ => vec![ty]
+                ty::TyTuple(ref tys) => tys.last().cloned(),
+                _ => Some(ty)
             })
             .filter(|ty| *ty != tcx.types.bool)
             .collect();
index f93332e07737d52bd787f9e9062a39d77b9c8fe8..2dda63802e0f2dd0ff780649453bebc99edfdfaf 100644 (file)
@@ -280,6 +280,22 @@ fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) {
         }
     }
 
+    fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
+        if !subty.has_escaping_regions() {
+            let cause = self.cause(cause);
+            match traits::trait_ref_for_builtin_bound(self.infcx.tcx,
+                                                      ty::BoundSized,
+                                                      subty) {
+                Ok(trait_ref) => {
+                    self.out.push(
+                        traits::Obligation::new(cause,
+                                                trait_ref.to_predicate()));
+                }
+                Err(ErrorReported) => { }
+            }
+        }
+    }
+
     /// Push new obligations into `out`. Returns true if it was able
     /// to generate all the predicates needed to validate that `ty0`
     /// is WF. Returns false if `ty0` is an unresolved type variable,
@@ -301,23 +317,18 @@ fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
 
                 ty::TySlice(subty) |
                 ty::TyArray(subty, _) => {
-                    if !subty.has_escaping_regions() {
-                        let cause = self.cause(traits::SliceOrArrayElem);
-                        match traits::trait_ref_for_builtin_bound(self.infcx.tcx,
-                                                                  ty::BoundSized,
-                                                                  subty) {
-                            Ok(trait_ref) => {
-                                self.out.push(
-                                    traits::Obligation::new(cause,
-                                                            trait_ref.to_predicate()));
-                            }
-                            Err(ErrorReported) => { }
+                    self.require_sized(subty, traits::SliceOrArrayElem);
+                }
+
+                ty::TyTuple(ref tys) => {
+                    if let Some((_last, rest)) = tys.split_last() {
+                        for elem in rest {
+                            self.require_sized(elem, traits::TupleElem);
                         }
                     }
                 }
 
                 ty::TyBox(_) |
-                ty::TyTuple(_) |
                 ty::TyRawPtr(_) => {
                     // simple cases that are WF if their type args are WF
                 }
index f88165c02e988cd5e34bc3af44292b6cdb0d2a9c..1d93645fc847f6c3dfcd6750f7dc3271c7771035 100644 (file)
@@ -60,6 +60,7 @@ fn f8<X: ?Sized>(x1: &S<X>, x2: &S<X>) {
 fn f9<X: ?Sized>(x1: Box<S<X>>, x2: Box<E<X>>) {
     f5(&(*x1, 34));
     //~^ ERROR `X: std::marker::Sized` is not satisfied
+    //~^^ ERROR `X: std::marker::Sized` is not satisfied
 }
 
 fn f10<X: ?Sized>(x1: Box<S<X>>, x2: Box<E<X>>) {
index 663cb0a17161a6b26263bc3f6b7a8f090c77bcce..e18ccfee96c7da7994b4f4aec09576a28f89e796 100644 (file)
@@ -14,9 +14,9 @@ trait T {}
 
 fn f1<X: ?Sized>(x: &X) {
     let _: X; // <-- this is OK, no bindings created, no initializer.
-    let _: (isize, (X, isize)); // same
+    let _: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied
     let y: X; //~ERROR `X: std::marker::Sized` is not satisfied
-    let y: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied
+    let y: (isize, (X, usize)); //~ERROR `X: std::marker::Sized` is not satisfied
 }
 fn f2<X: ?Sized + T>(x: &X) {
     let y: X; //~ERROR `X: std::marker::Sized` is not satisfied