Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 686ec28

Browse files
committedJun 29, 2017
Auto merge of #42527 - qnighy:unsized-tuple-coercions, r=arielb1
Unsized tuple coercions Part of #18469. Fixes #32702. #37685 and #34451 might also be related. This PR does the following: - Introduce explicit `Sized` constraints on tuple initializers, similar to that of record-struct initializers. Not much relevant to the main contribution but I noticed this when making tests for unsized tuple coercions. - Implement `(.., T): Unsize<(.., U)>` where `T: Unsize<U>`. - Assume `(.., T)` is MaybeUnsizedUnivariant. - Modify `src/librustc/ty/util.rs` and `src/librustc_trans/glue.rs` so that tuples and structs are uniformly traversed when translating.
2 parents d0e0f53 + 94862c6 commit 686ec28

26 files changed

+707
-19
lines changed
 
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# `unsized_tuple_coercion`
2+
3+
The tracking issue for this feature is: [#42877]
4+
5+
[#42877]: https://github.com/rust-lang/rust/issues/42877
6+
7+
------------------------
8+
9+
This is a part of [RFC0401]. According to the RFC, there should be an implementation like this:
10+
11+
```rust
12+
impl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized<U> {}
13+
```
14+
15+
This implementation is currently gated behind `#[feature(unsized_tuple_coercion)]` to avoid insta-stability. Therefore you can use it like this:
16+
17+
```rust
18+
#![feature(unsized_tuple_coercion)]
19+
20+
fn main() {
21+
let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]);
22+
let y : &([i32; 3], [i32]) = &x;
23+
assert_eq!(y.1[0], 4);
24+
}
25+
```
26+
27+
[RFC0401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md

‎src/librustc/traits/error_reporting.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
10601060
err.note("slice and array elements must have `Sized` type");
10611061
}
10621062
ObligationCauseCode::TupleElem => {
1063-
err.note("tuple elements must have `Sized` type");
1063+
err.note("only the last element of a tuple may have a dynamically sized type");
10641064
}
10651065
ObligationCauseCode::ProjectionWf(data) => {
10661066
err.note(&format!("required so that the projection `{}` is well-formed",
@@ -1097,6 +1097,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
10971097
ObligationCauseCode::AssignmentLhsSized => {
10981098
err.note("the left-hand-side of an assignment must have a statically known size");
10991099
}
1100+
ObligationCauseCode::TupleInitializerSized => {
1101+
err.note("tuples must have a statically known size to be initialized");
1102+
}
11001103
ObligationCauseCode::StructInitializerSized => {
11011104
err.note("structs must have a statically known size to be initialized");
11021105
}

‎src/librustc/traits/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ pub enum ObligationCauseCode<'tcx> {
121121
// Various cases where expressions must be sized/copy/etc:
122122
/// L = X implies that L is Sized
123123
AssignmentLhsSized,
124+
/// (x1, .., xn) must be Sized
125+
TupleInitializerSized,
124126
/// S { ... } must be Sized
125127
StructInitializerSized,
126128
/// Type of each variable must be Sized

‎src/librustc/traits/select.rs

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1651,6 +1651,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
16511651
def_id_a == def_id_b
16521652
}
16531653

1654+
// (.., T) -> (.., U).
1655+
(&ty::TyTuple(tys_a, _), &ty::TyTuple(tys_b, _)) => {
1656+
tys_a.len() == tys_b.len()
1657+
}
1658+
16541659
_ => false
16551660
};
16561661

@@ -2591,8 +2596,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
25912596
let inner_source = field.subst(tcx, substs_a);
25922597
let inner_target = field.subst(tcx, substs_b);
25932598

2594-
// Check that the source structure with the target's
2595-
// type parameters is a subtype of the target.
2599+
// Check that the source struct with the target's
2600+
// unsized parameters is equal to the target.
25962601
let params = substs_a.iter().enumerate().map(|(i, &k)| {
25972602
if ty_params.contains(i) {
25982603
Kind::from(substs_b.type_at(i))
@@ -2617,6 +2622,37 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
26172622
&[inner_target]));
26182623
}
26192624

2625+
// (.., T) -> (.., U).
2626+
(&ty::TyTuple(tys_a, _), &ty::TyTuple(tys_b, _)) => {
2627+
assert_eq!(tys_a.len(), tys_b.len());
2628+
2629+
// The last field of the tuple has to exist.
2630+
let (a_last, a_mid) = if let Some(x) = tys_a.split_last() {
2631+
x
2632+
} else {
2633+
return Err(Unimplemented);
2634+
};
2635+
let b_last = tys_b.last().unwrap();
2636+
2637+
// Check that the source tuple with the target's
2638+
// last element is equal to the target.
2639+
let new_tuple = tcx.mk_tup(a_mid.iter().chain(Some(b_last)), false);
2640+
let InferOk { obligations, .. } =
2641+
self.infcx.at(&obligation.cause, obligation.param_env)
2642+
.eq(target, new_tuple)
2643+
.map_err(|_| Unimplemented)?;
2644+
self.inferred_obligations.extend(obligations);
2645+
2646+
// Construct the nested T: Unsize<U> predicate.
2647+
nested.push(tcx.predicate_for_trait_def(
2648+
obligation.param_env,
2649+
obligation.cause.clone(),
2650+
obligation.predicate.def_id(),
2651+
obligation.recursion_depth + 1,
2652+
a_last,
2653+
&[b_last]));
2654+
}
2655+
26202656
_ => bug!()
26212657
};
26222658

‎src/librustc/traits/structural_impls.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
189189
tcx.lift(&ty).map(super::ObjectCastObligation)
190190
}
191191
super::AssignmentLhsSized => Some(super::AssignmentLhsSized),
192+
super::TupleInitializerSized => Some(super::TupleInitializerSized),
192193
super::StructInitializerSized => Some(super::StructInitializerSized),
193194
super::VariableType(id) => Some(super::VariableType(id)),
194195
super::ReturnType(id) => Some(super::ReturnType(id)),
@@ -476,6 +477,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
476477
super::TupleElem |
477478
super::ItemObligation(_) |
478479
super::AssignmentLhsSized |
480+
super::TupleInitializerSized |
479481
super::StructInitializerSized |
480482
super::VariableType(_) |
481483
super::ReturnType(_) |
@@ -523,6 +525,7 @@ impl<'tcx> TypeFoldable<'tcx> for traits::ObligationCauseCode<'tcx> {
523525
super::TupleElem |
524526
super::ItemObligation(_) |
525527
super::AssignmentLhsSized |
528+
super::TupleInitializerSized |
526529
super::StructInitializerSized |
527530
super::VariableType(_) |
528531
super::ReturnType(_) |

‎src/librustc/ty/layout.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,12 +1220,16 @@ impl<'a, 'tcx> Layout {
12201220
}
12211221

12221222
ty::TyTuple(tys, _) => {
1223-
// FIXME(camlorn): if we ever allow unsized tuples, this needs to be checked.
1224-
// See the univariant case below to learn how.
1223+
let kind = if tys.len() == 0 {
1224+
StructKind::AlwaysSizedUnivariant
1225+
} else {
1226+
StructKind::MaybeUnsizedUnivariant
1227+
};
1228+
12251229
let st = Struct::new(dl,
12261230
&tys.iter().map(|ty| ty.layout(tcx, param_env))
12271231
.collect::<Result<Vec<_>, _>>()?,
1228-
&ReprOptions::default(), StructKind::AlwaysSizedUnivariant, ty)?;
1232+
&ReprOptions::default(), kind, ty)?;
12291233
Univariant { variant: st, non_zero: false }
12301234
}
12311235

‎src/librustc/ty/util.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -317,15 +317,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
317317
target: Ty<'tcx>)
318318
-> (Ty<'tcx>, Ty<'tcx>) {
319319
let (mut a, mut b) = (source, target);
320-
while let (&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs)) = (&a.sty, &b.sty) {
321-
if a_def != b_def || !a_def.is_struct() {
322-
break;
323-
}
324-
match a_def.struct_variant().fields.last() {
325-
Some(f) => {
326-
a = f.ty(self, a_substs);
327-
b = f.ty(self, b_substs);
328-
}
320+
loop {
321+
match (&a.sty, &b.sty) {
322+
(&TyAdt(a_def, a_substs), &TyAdt(b_def, b_substs))
323+
if a_def == b_def && a_def.is_struct() => {
324+
if let Some(f) = a_def.struct_variant().fields.last() {
325+
a = f.ty(self, a_substs);
326+
b = f.ty(self, b_substs);
327+
} else {
328+
break;
329+
}
330+
},
331+
(&TyTuple(a_tys, _), &TyTuple(b_tys, _))
332+
if a_tys.len() == b_tys.len() => {
333+
if let Some(a_last) = a_tys.last() {
334+
a = a_last;
335+
b = b_tys.last().unwrap();
336+
} else {
337+
break;
338+
}
339+
},
329340
_ => break,
330341
}
331342
}

‎src/librustc_trans/glue.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
7676
}
7777
assert!(!info.is_null());
7878
match t.sty {
79-
ty::TyAdt(def, substs) => {
79+
ty::TyAdt(..) | ty::TyTuple(..) => {
8080
let ccx = bcx.ccx;
8181
// First get the size of all statically known fields.
8282
// Don't use size_of because it also rounds up to alignment, which we
@@ -101,8 +101,14 @@ pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, inf
101101

102102
// Recurse to get the size of the dynamically sized field (must be
103103
// the last field).
104-
let last_field = def.struct_variant().fields.last().unwrap();
105-
let field_ty = monomorphize::field_ty(bcx.tcx(), substs, last_field);
104+
let field_ty = match t.sty {
105+
ty::TyAdt(def, substs) => {
106+
let last_field = def.struct_variant().fields.last().unwrap();
107+
monomorphize::field_ty(bcx.tcx(), substs, last_field)
108+
},
109+
ty::TyTuple(tys, _) => tys.last().unwrap(),
110+
_ => unreachable!(),
111+
};
106112
let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
107113

108114
// FIXME (#26403, #27023): We should be adding padding

‎src/librustc_typeck/check/coercion.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ use rustc::ty::relate::RelateResult;
7676
use rustc::ty::subst::Subst;
7777
use errors::DiagnosticBuilder;
7878
use syntax::abi;
79+
use syntax::feature_gate;
7980
use syntax::ptr::P;
8081
use syntax_pos;
8182

@@ -520,14 +521,24 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
520521
coerce_source,
521522
&[coerce_target]));
522523

524+
let mut has_unsized_tuple_coercion = false;
525+
523526
// Keep resolving `CoerceUnsized` and `Unsize` predicates to avoid
524527
// emitting a coercion in cases like `Foo<$1>` -> `Foo<$2>`, where
525528
// inference might unify those two inner type variables later.
526529
let traits = [coerce_unsized_did, unsize_did];
527530
while let Some(obligation) = queue.pop_front() {
528531
debug!("coerce_unsized resolve step: {:?}", obligation);
529532
let trait_ref = match obligation.predicate {
530-
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => tr.clone(),
533+
ty::Predicate::Trait(ref tr) if traits.contains(&tr.def_id()) => {
534+
if unsize_did == tr.def_id() {
535+
if let ty::TyTuple(..) = tr.0.input_types().nth(1).unwrap().sty {
536+
debug!("coerce_unsized: found unsized tuple coercion");
537+
has_unsized_tuple_coercion = true;
538+
}
539+
}
540+
tr.clone()
541+
}
531542
_ => {
532543
coercion.obligations.push(obligation);
533544
continue;
@@ -557,6 +568,14 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
557568
}
558569
}
559570

571+
if has_unsized_tuple_coercion && !self.tcx.sess.features.borrow().unsized_tuple_coercion {
572+
feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
573+
"unsized_tuple_coercion",
574+
self.cause.span,
575+
feature_gate::GateIssue::Language,
576+
feature_gate::EXPLAIN_UNSIZED_TUPLE_COERCION);
577+
}
578+
560579
Ok(coercion)
561580
}
562581

‎src/librustc_typeck/check/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3854,6 +3854,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
38543854
if tuple.references_error() {
38553855
tcx.types.err
38563856
} else {
3857+
self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized);
38573858
tuple
38583859
}
38593860
}

‎src/libsyntax/feature_gate.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,9 @@ declare_features! (
357357

358358
// Allows a test to fail without failing the whole suite
359359
(active, allow_fail, "1.19.0", Some(42219)),
360+
361+
// Allows unsized tuple coercion.
362+
(active, unsized_tuple_coercion, "1.20.0", Some(42877)),
360363
);
361364

362365
declare_features! (
@@ -1041,6 +1044,9 @@ pub const EXPLAIN_VIS_MATCHER: &'static str =
10411044
pub const EXPLAIN_PLACEMENT_IN: &'static str =
10421045
"placement-in expression syntax is experimental and subject to change.";
10431046

1047+
pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &'static str =
1048+
"Unsized tuple coercion is not stable enough for use and is subject to change";
1049+
10441050
struct PostExpansionVisitor<'a> {
10451051
context: &'a Context<'a>,
10461052
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Forbid assignment into a dynamically sized type.
12+
13+
#![feature(unsized_tuple_coercion)]
14+
15+
type Fat<T: ?Sized> = (isize, &'static str, T);
16+
//~^ WARNING trait bounds are not (yet) enforced
17+
18+
#[derive(PartialEq,Eq)]
19+
struct Bar;
20+
21+
#[derive(PartialEq,Eq)]
22+
struct Bar1 {
23+
f: isize
24+
}
25+
26+
trait ToBar {
27+
fn to_bar(&self) -> Bar;
28+
fn to_val(&self) -> isize;
29+
}
30+
31+
impl ToBar for Bar1 {
32+
fn to_bar(&self) -> Bar {
33+
Bar
34+
}
35+
fn to_val(&self) -> isize {
36+
self.f
37+
}
38+
}
39+
40+
pub fn main() {
41+
// Assignment.
42+
let f5: &mut Fat<ToBar> = &mut (5, "some str", Bar1 {f :42});
43+
let z: Box<ToBar> = Box::new(Bar1 {f: 36});
44+
f5.2 = Bar1 {f: 36};
45+
//~^ ERROR mismatched types
46+
//~| expected type `ToBar`
47+
//~| found type `Bar1`
48+
//~| expected trait ToBar, found struct `Bar1`
49+
//~| ERROR `ToBar: std::marker::Sized` is not satisfied
50+
}

‎src/test/compile-fail/dst-bad-coerce1.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
// Attempt to change the type as well as unsizing.
1212

13+
#![feature(unsized_tuple_coercion)]
14+
1315
struct Fat<T: ?Sized> {
1416
ptr: T
1517
}
@@ -29,4 +31,16 @@ pub fn main() {
2931
let f2: &Fat<Foo> = &f1;
3032
let f3: &Fat<Bar> = f2;
3133
//~^ ERROR `Foo: Bar` is not satisfied
34+
35+
// Tuple with a vec of isize.
36+
let f1 = ([1, 2, 3],);
37+
let f2: &([isize; 3],) = &f1;
38+
let f3: &([usize],) = f2;
39+
//~^ ERROR mismatched types
40+
41+
// Tuple with a trait.
42+
let f1 = (Foo,);
43+
let f2: &(Foo,) = &f1;
44+
let f3: &(Bar,) = f2;
45+
//~^ ERROR `Foo: Bar` is not satisfied
3246
}

‎src/test/compile-fail/dst-bad-coerce2.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,14 @@ pub fn main() {
2828
let f1 = Fat { ptr: Foo };
2929
let f2: &Fat<Foo> = &f1;
3030
let f3: &mut Fat<Bar> = f2; //~ ERROR mismatched types
31+
32+
// Tuple with a vec of ints.
33+
let f1 = ([1, 2, 3],);
34+
let f2: &([isize; 3],) = &f1;
35+
let f3: &mut ([isize],) = f2; //~ ERROR mismatched types
36+
37+
// Tuple with a trait.
38+
let f1 = (Foo,);
39+
let f2: &(Foo,) = &f1;
40+
let f3: &mut (Bar,) = f2; //~ ERROR mismatched types
3141
}

‎src/test/compile-fail/dst-bad-coerce3.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
// Attempt to extend the lifetime as well as unsizing.
1212

13+
#![feature(unsized_tuple_coercion)]
14+
1315
struct Fat<T: ?Sized> {
1416
ptr: T
1517
}
@@ -28,6 +30,16 @@ fn baz<'a>() {
2830
let f1 = Fat { ptr: Foo };
2931
let f2: &Fat<Foo> = &f1; //~ ERROR `f1` does not live long enough
3032
let f3: &'a Fat<Bar> = f2;
33+
34+
// Tuple with a vec of ints.
35+
let f1 = ([1, 2, 3],);
36+
let f2: &([isize; 3],) = &f1; //~ ERROR `f1` does not live long enough
37+
let f3: &'a ([isize],) = f2;
38+
39+
// Tuple with a trait.
40+
let f1 = (Foo,);
41+
let f2: &(Foo,) = &f1; //~ ERROR `f1` does not live long enough
42+
let f3: &'a (Bar,) = f2;
3143
}
3244

3345
pub fn main() {

‎src/test/compile-fail/dst-bad-coerce4.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
// Attempt to coerce from unsized to sized.
1212

13+
#![feature(unsized_tuple_coercion)]
14+
1315
struct Fat<T: ?Sized> {
1416
ptr: T
1517
}
@@ -22,4 +24,12 @@ pub fn main() {
2224
//~| expected type `&Fat<[isize; 3]>`
2325
//~| found type `&Fat<[isize]>`
2426
//~| expected array of 3 elements, found slice
27+
28+
// Tuple with a vec of isizes.
29+
let f1: &([isize],) = &([1, 2, 3],);
30+
let f2: &([isize; 3],) = f1;
31+
//~^ ERROR mismatched types
32+
//~| expected type `&([isize; 3],)`
33+
//~| found type `&([isize],)`
34+
//~| expected array of 3 elements, found slice
2535
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Try to initialise a DST struct where the lost information is deeply nested.
12+
// This is an error because it requires an unsized rvalue. This is a problem
13+
// because it would require stack allocation of an unsized temporary (*g in the
14+
// test).
15+
16+
#![feature(unsized_tuple_coercion)]
17+
18+
pub fn main() {
19+
let f: ([isize; 3],) = ([5, 6, 7],);
20+
let g: &([isize],) = &f;
21+
let h: &(([isize],),) = &(*g,);
22+
//~^ ERROR `[isize]: std::marker::Sized` is not satisfied
23+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
let _ : &(Send,) = &((),);
13+
//~^ ERROR Unsized tuple coercion is not stable enough
14+
}

‎src/test/compile-fail/unsized3.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ fn f9<X: ?Sized>(x1: Box<S<X>>) {
5454
fn f10<X: ?Sized>(x1: Box<S<X>>) {
5555
f5(&(32, *x1));
5656
//~^ ERROR `X: std::marker::Sized` is not satisfied
57+
//~| ERROR `X: std::marker::Sized` is not satisfied
5758
}
5859

5960
pub fn main() {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// no-prefer-dynamic
12+
13+
#![feature(unsized_tuple_coercion)]
14+
15+
static mut DROP_RAN: bool = false;
16+
17+
struct Foo;
18+
impl Drop for Foo {
19+
fn drop(&mut self) {
20+
unsafe { DROP_RAN = true; }
21+
}
22+
}
23+
24+
trait Trait { fn dummy(&self) { } }
25+
impl Trait for Foo {}
26+
27+
pub fn main() {
28+
{
29+
let _x: Box<(i32, Trait)> = Box::<(i32, Foo)>::new((42, Foo));
30+
}
31+
unsafe {
32+
assert!(DROP_RAN);
33+
}
34+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// no-prefer-dynamic
12+
13+
#![feature(unsized_tuple_coercion)]
14+
15+
static mut DROP_RAN: isize = 0;
16+
17+
struct Foo;
18+
impl Drop for Foo {
19+
fn drop(&mut self) {
20+
unsafe { DROP_RAN += 1; }
21+
}
22+
}
23+
24+
pub fn main() {
25+
{
26+
let _x: Box<(i32, [Foo])> = Box::<(i32, [Foo; 3])>::new((42, [Foo, Foo, Foo]));
27+
}
28+
unsafe {
29+
assert_eq!(DROP_RAN, 3);
30+
}
31+
}

‎src/test/run-pass/dst-irrefutable-bind.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
#![feature(unsized_tuple_coercion)]
12+
1113
struct Test<T: ?Sized>(T);
1214

1315
fn main() {
@@ -21,4 +23,14 @@ fn main() {
2123
let slice = &[1,2,3];
2224
let x = Test(&slice);
2325
let Test(&_slice) = x;
26+
27+
28+
let x = (10, [1,2,3]);
29+
let x : &(i32, [i32]) = &x;
30+
31+
let & ref _y = x;
32+
33+
let slice = &[1,2,3];
34+
let x = (10, &slice);
35+
let (_, &_slice) = x;
2436
}

‎src/test/run-pass/dst-raw.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
// Test DST raw pointers
1212

1313

14+
#![feature(unsized_tuple_coercion)]
15+
1416
trait Trait {
1517
fn foo(&self) -> isize;
1618
}
@@ -45,6 +47,14 @@ pub fn main() {
4547
};
4648
assert_eq!(r, 42);
4749

50+
// raw DST tuple
51+
let p = (A { f: 42 },);
52+
let o: *const (Trait,) = &p;
53+
let r = unsafe {
54+
(&*o).0.foo()
55+
};
56+
assert_eq!(r, 42);
57+
4858
// raw slice
4959
let a: *const [_] = &[1, 2, 3];
5060
unsafe {
@@ -72,6 +82,15 @@ pub fn main() {
7282
assert_eq!(len, 3);
7383
}
7484

85+
// raw DST tuple with slice
86+
let c: *const ([_],) = &([1, 2, 3],);
87+
unsafe {
88+
let b = (&*c).0[0];
89+
assert_eq!(b, 1);
90+
let len = (&*c).0.len();
91+
assert_eq!(len, 3);
92+
}
93+
7594
// all of the above with *mut
7695
let mut x = A { f: 42 };
7796
let z: *mut Trait = &mut x;
@@ -87,6 +106,13 @@ pub fn main() {
87106
};
88107
assert_eq!(r, 42);
89108

109+
let mut p = (A { f: 42 },);
110+
let o: *mut (Trait,) = &mut p;
111+
let r = unsafe {
112+
(&*o).0.foo()
113+
};
114+
assert_eq!(r, 42);
115+
90116
let a: *mut [_] = &mut [1, 2, 3];
91117
unsafe {
92118
let b = (*a)[2];
@@ -110,4 +136,12 @@ pub fn main() {
110136
let len = (&*c).f.len();
111137
assert_eq!(len, 3);
112138
}
139+
140+
let c: *mut ([_],) = &mut ([1, 2, 3],);
141+
unsafe {
142+
let b = (&*c).0[0];
143+
assert_eq!(b, 1);
144+
let len = (&*c).0.len();
145+
assert_eq!(len, 3);
146+
}
113147
}

‎src/test/run-pass/dst-trait-tuple.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
#![allow(unused_features)]
13+
#![feature(box_syntax)]
14+
#![feature(unsized_tuple_coercion)]
15+
16+
type Fat<T: ?Sized> = (isize, &'static str, T);
17+
18+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
19+
struct Bar;
20+
21+
#[derive(Copy, Clone, PartialEq, Eq)]
22+
struct Bar1 {
23+
f: isize
24+
}
25+
26+
trait ToBar {
27+
fn to_bar(&self) -> Bar;
28+
fn to_val(&self) -> isize;
29+
}
30+
31+
impl ToBar for Bar {
32+
fn to_bar(&self) -> Bar {
33+
*self
34+
}
35+
fn to_val(&self) -> isize {
36+
0
37+
}
38+
}
39+
impl ToBar for Bar1 {
40+
fn to_bar(&self) -> Bar {
41+
Bar
42+
}
43+
fn to_val(&self) -> isize {
44+
self.f
45+
}
46+
}
47+
48+
// x is a fat pointer
49+
fn foo(x: &Fat<ToBar>) {
50+
assert_eq!(x.0, 5);
51+
assert_eq!(x.1, "some str");
52+
assert_eq!(x.2.to_bar(), Bar);
53+
assert_eq!(x.2.to_val(), 42);
54+
55+
let y = &x.2;
56+
assert_eq!(y.to_bar(), Bar);
57+
assert_eq!(y.to_val(), 42);
58+
}
59+
60+
fn bar(x: &ToBar) {
61+
assert_eq!(x.to_bar(), Bar);
62+
assert_eq!(x.to_val(), 42);
63+
}
64+
65+
fn baz(x: &Fat<Fat<ToBar>>) {
66+
assert_eq!(x.0, 5);
67+
assert_eq!(x.1, "some str");
68+
assert_eq!((x.2).0, 8);
69+
assert_eq!((x.2).1, "deep str");
70+
assert_eq!((x.2).2.to_bar(), Bar);
71+
assert_eq!((x.2).2.to_val(), 42);
72+
73+
let y = &(x.2).2;
74+
assert_eq!(y.to_bar(), Bar);
75+
assert_eq!(y.to_val(), 42);
76+
77+
}
78+
79+
pub fn main() {
80+
let f1 = (5, "some str", Bar1 {f :42});
81+
foo(&f1);
82+
let f2 = &f1;
83+
foo(f2);
84+
let f3: &Fat<ToBar> = f2;
85+
foo(f3);
86+
let f4: &Fat<ToBar> = &f1;
87+
foo(f4);
88+
let f5: &Fat<ToBar> = &(5, "some str", Bar1 {f :42});
89+
foo(f5);
90+
91+
// Zero size object.
92+
let f6: &Fat<ToBar> = &(5, "some str", Bar);
93+
assert_eq!(f6.2.to_bar(), Bar);
94+
95+
// &*
96+
//
97+
let f7: Box<ToBar> = Box::new(Bar1 {f :42});
98+
bar(&*f7);
99+
100+
// Deep nesting
101+
let f1 = (5, "some str", (8, "deep str", Bar1 {f :42}));
102+
baz(&f1);
103+
let f2 = &f1;
104+
baz(f2);
105+
let f3: &Fat<Fat<ToBar>> = f2;
106+
baz(f3);
107+
let f4: &Fat<Fat<ToBar>> = &f1;
108+
baz(f4);
109+
let f5: &Fat<Fat<ToBar>> = &(5, "some str", (8, "deep str", Bar1 {f :42}));
110+
baz(f5);
111+
}

‎src/test/run-pass/dst-tuple-sole.rs

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// As dst-tuple.rs, but the unsized field is the only field in the tuple.
12+
13+
14+
#![feature(unsized_tuple_coercion)]
15+
16+
type Fat<T: ?Sized> = (T,);
17+
18+
// x is a fat pointer
19+
fn foo(x: &Fat<[isize]>) {
20+
let y = &x.0;
21+
assert_eq!(x.0.len(), 3);
22+
assert_eq!(y[0], 1);
23+
assert_eq!(x.0[1], 2);
24+
}
25+
26+
fn foo2<T:ToBar>(x: &Fat<[T]>) {
27+
let y = &x.0;
28+
let bar = Bar;
29+
assert_eq!(x.0.len(), 3);
30+
assert_eq!(y[0].to_bar(), bar);
31+
assert_eq!(x.0[1].to_bar(), bar);
32+
}
33+
34+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
35+
struct Bar;
36+
37+
trait ToBar {
38+
fn to_bar(&self) -> Bar;
39+
}
40+
41+
impl ToBar for Bar {
42+
fn to_bar(&self) -> Bar {
43+
*self
44+
}
45+
}
46+
47+
pub fn main() {
48+
// With a vec of ints.
49+
let f1 = ([1, 2, 3],);
50+
foo(&f1);
51+
let f2 = &f1;
52+
foo(f2);
53+
let f3: &Fat<[isize]> = f2;
54+
foo(f3);
55+
let f4: &Fat<[isize]> = &f1;
56+
foo(f4);
57+
let f5: &Fat<[isize]> = &([1, 2, 3],);
58+
foo(f5);
59+
60+
// With a vec of Bars.
61+
let bar = Bar;
62+
let f1 = ([bar, bar, bar],);
63+
foo2(&f1);
64+
let f2 = &f1;
65+
foo2(f2);
66+
let f3: &Fat<[Bar]> = f2;
67+
foo2(f3);
68+
let f4: &Fat<[Bar]> = &f1;
69+
foo2(f4);
70+
let f5: &Fat<[Bar]> = &([bar, bar, bar],);
71+
foo2(f5);
72+
73+
// Assignment.
74+
let f5: &mut Fat<[isize]> = &mut ([1, 2, 3],);
75+
f5.0[1] = 34;
76+
assert_eq!(f5.0[0], 1);
77+
assert_eq!(f5.0[1], 34);
78+
assert_eq!(f5.0[2], 3);
79+
80+
// Zero size vec.
81+
let f5: &Fat<[isize]> = &([],);
82+
assert!(f5.0.is_empty());
83+
let f5: &Fat<[Bar]> = &([],);
84+
assert!(f5.0.is_empty());
85+
}

‎src/test/run-pass/dst-tuple.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
12+
#![allow(unknown_features)]
13+
#![feature(box_syntax)]
14+
#![feature(unsized_tuple_coercion)]
15+
16+
type Fat<T: ?Sized> = (isize, &'static str, T);
17+
18+
// x is a fat pointer
19+
fn foo(x: &Fat<[isize]>) {
20+
let y = &x.2;
21+
assert_eq!(x.2.len(), 3);
22+
assert_eq!(y[0], 1);
23+
assert_eq!(x.2[1], 2);
24+
assert_eq!(x.0, 5);
25+
assert_eq!(x.1, "some str");
26+
}
27+
28+
fn foo2<T:ToBar>(x: &Fat<[T]>) {
29+
let y = &x.2;
30+
let bar = Bar;
31+
assert_eq!(x.2.len(), 3);
32+
assert_eq!(y[0].to_bar(), bar);
33+
assert_eq!(x.2[1].to_bar(), bar);
34+
assert_eq!(x.0, 5);
35+
assert_eq!(x.1, "some str");
36+
}
37+
38+
fn foo3(x: &Fat<Fat<[isize]>>) {
39+
let y = &(x.2).2;
40+
assert_eq!(x.0, 5);
41+
assert_eq!(x.1, "some str");
42+
assert_eq!((x.2).0, 8);
43+
assert_eq!((x.2).1, "deep str");
44+
assert_eq!((x.2).2.len(), 3);
45+
assert_eq!(y[0], 1);
46+
assert_eq!((x.2).2[1], 2);
47+
}
48+
49+
50+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
51+
struct Bar;
52+
53+
trait ToBar {
54+
fn to_bar(&self) -> Bar;
55+
}
56+
57+
impl ToBar for Bar {
58+
fn to_bar(&self) -> Bar {
59+
*self
60+
}
61+
}
62+
63+
pub fn main() {
64+
// With a vec of ints.
65+
let f1 = (5, "some str", [1, 2, 3]);
66+
foo(&f1);
67+
let f2 = &f1;
68+
foo(f2);
69+
let f3: &Fat<[isize]> = f2;
70+
foo(f3);
71+
let f4: &Fat<[isize]> = &f1;
72+
foo(f4);
73+
let f5: &Fat<[isize]> = &(5, "some str", [1, 2, 3]);
74+
foo(f5);
75+
76+
// With a vec of Bars.
77+
let bar = Bar;
78+
let f1 = (5, "some str", [bar, bar, bar]);
79+
foo2(&f1);
80+
let f2 = &f1;
81+
foo2(f2);
82+
let f3: &Fat<[Bar]> = f2;
83+
foo2(f3);
84+
let f4: &Fat<[Bar]> = &f1;
85+
foo2(f4);
86+
let f5: &Fat<[Bar]> = &(5, "some str", [bar, bar, bar]);
87+
foo2(f5);
88+
89+
// Assignment.
90+
let f5: &mut Fat<[isize]> = &mut (5, "some str", [1, 2, 3]);
91+
f5.2[1] = 34;
92+
assert_eq!(f5.2[0], 1);
93+
assert_eq!(f5.2[1], 34);
94+
assert_eq!(f5.2[2], 3);
95+
96+
// Zero size vec.
97+
let f5: &Fat<[isize]> = &(5, "some str", []);
98+
assert!(f5.2.is_empty());
99+
let f5: &Fat<[Bar]> = &(5, "some str", []);
100+
assert!(f5.2.is_empty());
101+
102+
// Deeply nested.
103+
let f1 = (5, "some str", (8, "deep str", [1, 2, 3]));
104+
foo3(&f1);
105+
let f2 = &f1;
106+
foo3(f2);
107+
let f3: &Fat<Fat<[isize]>> = f2;
108+
foo3(f3);
109+
let f4: &Fat<Fat<[isize]>> = &f1;
110+
foo3(f4);
111+
let f5: &Fat<Fat<[isize]>> = &(5, "some str", (8, "deep str", [1, 2, 3]));
112+
foo3(f5);
113+
114+
// Box.
115+
let f1 = Box::new([1, 2, 3]);
116+
assert_eq!((*f1)[1], 2);
117+
let f2: Box<[isize]> = f1;
118+
assert_eq!((*f2)[1], 2);
119+
120+
// Nested Box.
121+
let f1 : Box<Fat<[isize; 3]>> = box (5, "some str", [1, 2, 3]);
122+
foo(&*f1);
123+
let f2 : Box<Fat<[isize]>> = f1;
124+
foo(&*f2);
125+
126+
let f3 : Box<Fat<[isize]>> =
127+
Box::<Fat<[_; 3]>>::new((5, "some str", [1, 2, 3]));
128+
foo(&*f3);
129+
}

0 commit comments

Comments
 (0)
Please sign in to comment.