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.
This commit is contained in:
Ariel Ben-Yehuda 2016-04-22 01:46:23 +03:00
parent babb5df529
commit 0a6dfc5177
8 changed files with 46 additions and 19 deletions

View File

@ -33,7 +33,7 @@ use mem;
use intrinsics; use intrinsics;
/// Arithmetic operations required by bignums. /// Arithmetic operations required by bignums.
pub trait FullOps { pub trait FullOps: Sized {
/// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`, /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
/// where `W` is the number of bits in `Self`. /// where `W` is the number of bits in `Self`.
fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self); fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self);

View File

@ -764,6 +764,11 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
ObligationCauseCode::SliceOrArrayElem => { ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type"); 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) => { ObligationCauseCode::ProjectionWf(data) => {
err.note(&format!("required so that the projection `{}` is well-formed", err.note(&format!("required so that the projection `{}` is well-formed",
data)); data));

View File

@ -106,9 +106,12 @@ pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from span. /// Not well classified or should be obvious from span.
MiscObligation, MiscObligation,
/// This is the trait reference from the given projection /// A slice or array is WF only if `T: Sized`
SliceOrArrayElem, SliceOrArrayElem,
/// A tuple is WF only if its middle elements are Sized
TupleElem,
/// This is the trait reference from the given projection /// This is the trait reference from the given projection
ProjectionWf(ty::ProjectionTy<'tcx>), ProjectionWf(ty::ProjectionTy<'tcx>),

View File

@ -1652,7 +1652,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) |
ty::TyChar | ty::TyBox(_) | ty::TyRef(..) | ty::TyChar | ty::TyBox(_) | ty::TyRef(..) |
ty::TyArray(..) | ty::TyTuple(..) | ty::TyClosure(..) | ty::TyArray(..) | ty::TyClosure(..) |
ty::TyError => { ty::TyError => {
// safe for everything // safe for everything
Where(ty::Binder(Vec::new())) Where(ty::Binder(Vec::new()))
@ -1660,6 +1660,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never, 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) => { ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
let sized_crit = def.sized_constraint(self.tcx()); let sized_crit = def.sized_constraint(self.tcx());
// (*) binder moved here // (*) binder moved here

View File

@ -1761,8 +1761,8 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
let tys : Vec<_> = tys.into_iter() let tys : Vec<_> = tys.into_iter()
.map(|ty| self.sized_constraint_for_ty(tcx, stack, ty)) .map(|ty| self.sized_constraint_for_ty(tcx, stack, ty))
.flat_map(|ty| match ty.sty { .flat_map(|ty| match ty.sty {
ty::TyTuple(ref tys) => tys.clone(), ty::TyTuple(ref tys) => tys.last().cloned(),
_ => vec![ty] _ => Some(ty)
}) })
.filter(|ty| *ty != tcx.types.bool) .filter(|ty| *ty != tcx.types.bool)
.collect(); .collect();

View File

@ -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 /// Push new obligations into `out`. Returns true if it was able
/// to generate all the predicates needed to validate that `ty0` /// to generate all the predicates needed to validate that `ty0`
/// is WF. Returns false if `ty0` is an unresolved type variable, /// 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::TySlice(subty) |
ty::TyArray(subty, _) => { ty::TyArray(subty, _) => {
if !subty.has_escaping_regions() { self.require_sized(subty, traits::SliceOrArrayElem);
let cause = self.cause(traits::SliceOrArrayElem); }
match traits::trait_ref_for_builtin_bound(self.infcx.tcx,
ty::BoundSized, ty::TyTuple(ref tys) => {
subty) { if let Some((_last, rest)) = tys.split_last() {
Ok(trait_ref) => { for elem in rest {
self.out.push( self.require_sized(elem, traits::TupleElem);
traits::Obligation::new(cause,
trait_ref.to_predicate()));
}
Err(ErrorReported) => { }
} }
} }
} }
ty::TyBox(_) | ty::TyBox(_) |
ty::TyTuple(_) |
ty::TyRawPtr(_) => { ty::TyRawPtr(_) => {
// simple cases that are WF if their type args are WF // simple cases that are WF if their type args are WF
} }

View 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>>) { fn f9<X: ?Sized>(x1: Box<S<X>>, x2: Box<E<X>>) {
f5(&(*x1, 34)); f5(&(*x1, 34));
//~^ ERROR `X: std::marker::Sized` is not satisfied //~^ 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>>) { fn f10<X: ?Sized>(x1: Box<S<X>>, x2: Box<E<X>>) {

View File

@ -14,9 +14,9 @@ trait T {}
fn f1<X: ?Sized>(x: &X) { fn f1<X: ?Sized>(x: &X) {
let _: X; // <-- this is OK, no bindings created, no initializer. 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: 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) { fn f2<X: ?Sized + T>(x: &X) {
let y: X; //~ERROR `X: std::marker::Sized` is not satisfied let y: X; //~ERROR `X: std::marker::Sized` is not satisfied