about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2016-04-22 01:46:23 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2016-05-03 18:30:10 +0300
commit0a6dfc51777eb388b6e795399bf1d3f8aac57db8 (patch)
tree01f67adda8847634fa5ae03b3005be6868426f6c /src
parentbabb5df529ceef1cc8c12143d6dd4ab21188cc3e (diff)
downloadrust-0a6dfc51777eb388b6e795399bf1d3f8aac57db8.tar.gz
rust-0a6dfc51777eb388b6e795399bf1d3f8aac57db8.zip
require the non-last elements of a tuple to be Sized
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.
Diffstat (limited to 'src')
-rw-r--r--src/libcore/num/bignum.rs2
-rw-r--r--src/librustc/traits/error_reporting.rs5
-rw-r--r--src/librustc/traits/mod.rs5
-rw-r--r--src/librustc/traits/select.rs9
-rw-r--r--src/librustc/ty/mod.rs4
-rw-r--r--src/librustc/ty/wf.rs35
-rw-r--r--src/test/compile-fail/unsized3.rs1
-rw-r--r--src/test/compile-fail/unsized6.rs4
8 files changed, 46 insertions, 19 deletions
diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs
index 66c6deb3615..a881b539ced 100644
--- a/src/libcore/num/bignum.rs
+++ b/src/libcore/num/bignum.rs
@@ -33,7 +33,7 @@ use mem;
 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);
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 531a4fbf8be..d02dfcd9ea7 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -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));
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index a160465e2e8..5921cdeab78 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -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>),
 
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 3a208aba6d8..08a996c142d 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -1652,7 +1652,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, '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 @@ impl<'cx, 'tcx> SelectionContext<'cx, '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
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 179c8387376..b4156fde6a3 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1761,8 +1761,8 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
         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();
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index f93332e0773..2dda63802e0 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -280,6 +280,22 @@ impl<'a,'tcx> WfPredicates<'a,'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 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> {
 
                 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
                 }
diff --git a/src/test/compile-fail/unsized3.rs b/src/test/compile-fail/unsized3.rs
index f88165c02e9..1d93645fc84 100644
--- a/src/test/compile-fail/unsized3.rs
+++ b/src/test/compile-fail/unsized3.rs
@@ -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>>) {
diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs
index 663cb0a1716..e18ccfee96c 100644
--- a/src/test/compile-fail/unsized6.rs
+++ b/src/test/compile-fail/unsized6.rs
@@ -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