From 0a6dfc51777eb388b6e795399bf1d3f8aac57db8 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Fri, 22 Apr 2016 01:46:23 +0300 Subject: [PATCH] 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. --- src/libcore/num/bignum.rs | 2 +- src/librustc/traits/error_reporting.rs | 5 ++++ src/librustc/traits/mod.rs | 5 +++- src/librustc/traits/select.rs | 9 ++++++- src/librustc/ty/mod.rs | 4 +-- src/librustc/ty/wf.rs | 35 +++++++++++++++++--------- src/test/compile-fail/unsized3.rs | 1 + src/test/compile-fail/unsized6.rs | 4 +-- 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(x1: &S, x2: &S) { fn f9(x1: Box>, x2: Box>) { f5(&(*x1, 34)); //~^ ERROR `X: std::marker::Sized` is not satisfied + //~^^ ERROR `X: std::marker::Sized` is not satisfied } fn f10(x1: Box>, x2: Box>) { 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: &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: &X) { let y: X; //~ERROR `X: std::marker::Sized` is not satisfied