summaryrefslogtreecommitdiffstats
path: root/src/test/ui/dynamically-sized-types
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/ui/dynamically-sized-types')
-rw-r--r--src/test/ui/dynamically-sized-types/dst-coerce-custom.rs43
-rw-r--r--src/test/ui/dynamically-sized-types/dst-coerce-rc.rs42
-rw-r--r--src/test/ui/dynamically-sized-types/dst-coercions.rs28
-rw-r--r--src/test/ui/dynamically-sized-types/dst-deref-mut.rs35
-rw-r--r--src/test/ui/dynamically-sized-types/dst-deref.rs30
-rw-r--r--src/test/ui/dynamically-sized-types/dst-field-align.rs67
-rw-r--r--src/test/ui/dynamically-sized-types/dst-index.rs34
-rw-r--r--src/test/ui/dynamically-sized-types/dst-irrefutable-bind.rs27
-rw-r--r--src/test/ui/dynamically-sized-types/dst-raw.rs138
-rw-r--r--src/test/ui/dynamically-sized-types/dst-struct-sole.rs76
-rw-r--r--src/test/ui/dynamically-sized-types/dst-struct.rs122
-rw-r--r--src/test/ui/dynamically-sized-types/dst-trait-tuple.rs102
-rw-r--r--src/test/ui/dynamically-sized-types/dst-trait.rs105
-rw-r--r--src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs26
-rw-r--r--src/test/ui/dynamically-sized-types/dst-tuple-sole.rs79
-rw-r--r--src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs22
-rw-r--r--src/test/ui/dynamically-sized-types/dst-tuple.rs119
17 files changed, 1095 insertions, 0 deletions
diff --git a/src/test/ui/dynamically-sized-types/dst-coerce-custom.rs b/src/test/ui/dynamically-sized-types/dst-coerce-custom.rs
new file mode 100644
index 000000000..24d83eb53
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-coerce-custom.rs
@@ -0,0 +1,43 @@
+// run-pass
+// Test a very simple custom DST coercion.
+
+#![feature(unsize, coerce_unsized)]
+
+use std::ops::CoerceUnsized;
+use std::marker::Unsize;
+
+struct Bar<T: ?Sized> {
+ x: *const T,
+}
+
+impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Bar<U>> for Bar<T> {}
+
+trait Baz {
+ fn get(&self) -> i32;
+}
+
+impl Baz for i32 {
+ fn get(&self) -> i32 {
+ *self
+ }
+}
+
+fn main() {
+ // Arrays.
+ let a: Bar<[i32; 3]> = Bar { x: &[1, 2, 3] };
+ // This is the actual coercion.
+ let b: Bar<[i32]> = a;
+
+ unsafe {
+ assert_eq!((*b.x)[0], 1);
+ assert_eq!((*b.x)[1], 2);
+ assert_eq!((*b.x)[2], 3);
+ }
+
+ // Trait objects.
+ let a: Bar<i32> = Bar { x: &42 };
+ let b: Bar<dyn Baz> = a;
+ unsafe {
+ assert_eq!((*b.x).get(), 42);
+ }
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-coerce-rc.rs b/src/test/ui/dynamically-sized-types/dst-coerce-rc.rs
new file mode 100644
index 000000000..683fa6850
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-coerce-rc.rs
@@ -0,0 +1,42 @@
+// run-pass
+#![allow(unused_variables)]
+#![allow(stable_features)]
+// Test a very simple custom DST coercion.
+
+#![feature(core, rc_weak)]
+
+use std::cell::RefCell;
+use std::rc::{Rc, Weak};
+
+trait Baz {
+ fn get(&self) -> i32;
+}
+
+impl Baz for i32 {
+ fn get(&self) -> i32 {
+ *self
+ }
+}
+
+fn main() {
+ let a: Rc<[i32; 3]> = Rc::new([1, 2, 3]);
+ let b: Rc<[i32]> = a;
+ assert_eq!(b[0], 1);
+ assert_eq!(b[1], 2);
+ assert_eq!(b[2], 3);
+
+ let a: Rc<i32> = Rc::new(42);
+ let b: Rc<dyn Baz> = a.clone();
+ assert_eq!(b.get(), 42);
+
+ let c: Weak<i32> = Rc::downgrade(&a);
+ let d: Weak<dyn Baz> = c.clone();
+
+ let _c = b.clone();
+
+ let a: Rc<RefCell<i32>> = Rc::new(RefCell::new(42));
+ let b: Rc<RefCell<dyn Baz>> = a.clone();
+ assert_eq!(b.borrow().get(), 42);
+ // FIXME
+ let c: Weak<RefCell<dyn Baz>> = Rc::downgrade(&a) as Weak<_>;
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-coercions.rs b/src/test/ui/dynamically-sized-types/dst-coercions.rs
new file mode 100644
index 000000000..66688e93f
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-coercions.rs
@@ -0,0 +1,28 @@
+// run-pass
+#![allow(unused_variables)]
+// Test coercions involving DST and/or raw pointers
+
+// pretty-expanded FIXME #23616
+
+struct S;
+trait T { fn dummy(&self) { } }
+impl T for S {}
+
+pub fn main() {
+ let x: &dyn T = &S;
+ // Test we can convert from &-ptr to *-ptr of trait objects
+ let x: *const dyn T = &S;
+
+ // Test we can convert from &-ptr to *-ptr of struct pointer (not DST)
+ let x: *const S = &S;
+
+ // As above, but mut
+ let x: &mut dyn T = &mut S;
+ let x: *mut dyn T = &mut S;
+
+ let x: *mut S = &mut S;
+
+ // Test we can change the mutability from mut to const.
+ let x: &dyn T = &mut S;
+ let x: *const dyn T = &mut S;
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-deref-mut.rs b/src/test/ui/dynamically-sized-types/dst-deref-mut.rs
new file mode 100644
index 000000000..1d62f42bd
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-deref-mut.rs
@@ -0,0 +1,35 @@
+// run-pass
+// Test that a custom deref with a fat pointer return type does not ICE
+
+
+use std::ops::{Deref, DerefMut};
+
+pub struct Arr {
+ ptr: Box<[usize]>
+}
+
+impl Deref for Arr {
+ type Target = [usize];
+
+ fn deref(&self) -> &[usize] {
+ panic!();
+ }
+}
+
+impl DerefMut for Arr {
+ fn deref_mut(&mut self) -> &mut [usize] {
+ &mut *self.ptr
+ }
+}
+
+pub fn foo(arr: &mut Arr) {
+ let x: &mut [usize] = &mut **arr;
+ assert_eq!(x[0], 1);
+ assert_eq!(x[1], 2);
+ assert_eq!(x[2], 3);
+}
+
+fn main() {
+ let mut a = Arr { ptr: Box::new([1, 2, 3]) };
+ foo(&mut a);
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-deref.rs b/src/test/ui/dynamically-sized-types/dst-deref.rs
new file mode 100644
index 000000000..0a350bac1
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-deref.rs
@@ -0,0 +1,30 @@
+// run-pass
+// Test that a custom deref with a fat pointer return type does not ICE
+
+
+use std::ops::Deref;
+
+pub struct Arr {
+ ptr: Box<[usize]>
+}
+
+impl Deref for Arr {
+ type Target = [usize];
+
+ fn deref(&self) -> &[usize] {
+ &*self.ptr
+ }
+}
+
+pub fn foo(arr: &Arr) {
+ assert_eq!(arr.len(), 3);
+ let x: &[usize] = &**arr;
+ assert_eq!(x[0], 1);
+ assert_eq!(x[1], 2);
+ assert_eq!(x[2], 3);
+}
+
+fn main() {
+ let a = Arr { ptr: Box::new([1, 2, 3]) };
+ foo(&a);
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-field-align.rs b/src/test/ui/dynamically-sized-types/dst-field-align.rs
new file mode 100644
index 000000000..6c338e999
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-field-align.rs
@@ -0,0 +1,67 @@
+// run-pass
+#![allow(dead_code)]
+struct Foo<T: ?Sized> {
+ a: u16,
+ b: T
+}
+
+trait Bar {
+ fn get(&self) -> usize;
+}
+
+impl Bar for usize {
+ fn get(&self) -> usize { *self }
+}
+
+struct Baz<T: ?Sized> {
+ a: T
+}
+
+struct HasDrop<T: ?Sized> {
+ ptr: Box<usize>,
+ data: T
+}
+
+fn main() {
+ // Test that zero-offset works properly
+ let b : Baz<usize> = Baz { a: 7 };
+ assert_eq!(b.a.get(), 7);
+ let b : &Baz<dyn Bar> = &b;
+ assert_eq!(b.a.get(), 7);
+
+ // Test that the field is aligned properly
+ let f : Foo<usize> = Foo { a: 0, b: 11 };
+ assert_eq!(f.b.get(), 11);
+ let ptr1 : *const u8 = &f.b as *const _ as *const u8;
+
+ let f : &Foo<dyn Bar> = &f;
+ let ptr2 : *const u8 = &f.b as *const _ as *const u8;
+ assert_eq!(f.b.get(), 11);
+
+ // The pointers should be the same
+ assert_eq!(ptr1, ptr2);
+
+ // Test that nested DSTs work properly
+ let f : Foo<Foo<usize>> = Foo { a: 0, b: Foo { a: 1, b: 17 }};
+ assert_eq!(f.b.b.get(), 17);
+ let f : &Foo<Foo<dyn Bar>> = &f;
+ assert_eq!(f.b.b.get(), 17);
+
+ // Test that get the pointer via destructuring works
+
+ let f : Foo<usize> = Foo { a: 0, b: 11 };
+ let f : &Foo<dyn Bar> = &f;
+ let &Foo { a: _, b: ref bar } = f;
+ assert_eq!(bar.get(), 11);
+
+ // Make sure that drop flags don't screw things up
+
+ let d : HasDrop<Baz<[i32; 4]>> = HasDrop {
+ ptr: Box::new(0),
+ data: Baz { a: [1,2,3,4] }
+ };
+ assert_eq!([1,2,3,4], d.data.a);
+
+ let d : &HasDrop<Baz<[i32]>> = &d;
+ assert_eq!(&[1,2,3,4], &d.data.a);
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-index.rs b/src/test/ui/dynamically-sized-types/dst-index.rs
new file mode 100644
index 000000000..8aa65bbfd
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-index.rs
@@ -0,0 +1,34 @@
+// run-pass
+#![allow(unused_variables)]
+// Test that overloaded index expressions with DST result types
+// work and don't ICE.
+
+use std::ops::Index;
+use std::fmt::Debug;
+
+struct S;
+
+impl Index<usize> for S {
+ type Output = str;
+
+ fn index<'a>(&'a self, _: usize) -> &'a str {
+ "hello"
+ }
+}
+
+struct T;
+
+impl Index<usize> for T {
+ type Output = dyn Debug + 'static;
+
+ fn index<'a>(&'a self, idx: usize) -> &'a (dyn Debug + 'static) {
+ static X: usize = 42;
+ &X as &(dyn Debug + 'static)
+ }
+}
+
+fn main() {
+ assert_eq!(&S[0], "hello");
+ let _ = &T[0];
+ // let x = &x as &Debug;
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-irrefutable-bind.rs b/src/test/ui/dynamically-sized-types/dst-irrefutable-bind.rs
new file mode 100644
index 000000000..0a6c49111
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-irrefutable-bind.rs
@@ -0,0 +1,27 @@
+// run-pass
+#![feature(unsized_tuple_coercion)]
+
+struct Test<T: ?Sized>(T);
+
+fn main() {
+ let x = Test([1,2,3]);
+ let x : &Test<[i32]> = &x;
+
+ let & ref _y = x;
+
+ // Make sure binding to a fat pointer behind a reference
+ // still works
+ let slice = &[1,2,3];
+ let x = Test(&slice);
+ let Test(&_slice) = x;
+
+
+ let x = (10, [1,2,3]);
+ let x : &(i32, [i32]) = &x;
+
+ let & ref _y = x;
+
+ let slice = &[1,2,3];
+ let x = (10, &slice);
+ let (_, &_slice) = x;
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-raw.rs b/src/test/ui/dynamically-sized-types/dst-raw.rs
new file mode 100644
index 000000000..0893b02e7
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-raw.rs
@@ -0,0 +1,138 @@
+// run-pass
+// Test DST raw pointers
+
+
+#![feature(unsized_tuple_coercion)]
+
+trait Trait {
+ fn foo(&self) -> isize;
+}
+
+struct A {
+ f: isize
+}
+impl Trait for A {
+ fn foo(&self) -> isize {
+ self.f
+ }
+}
+
+struct Foo<T: ?Sized> {
+ f: T
+}
+
+pub fn main() {
+ // raw trait object
+ let x = A { f: 42 };
+ let z: *const dyn Trait = &x;
+ let r = unsafe {
+ (&*z).foo()
+ };
+ assert_eq!(r, 42);
+
+ // raw DST struct
+ let p = Foo {f: A { f: 42 }};
+ let o: *const Foo<dyn Trait> = &p;
+ let r = unsafe {
+ (&*o).f.foo()
+ };
+ assert_eq!(r, 42);
+
+ // raw DST tuple
+ let p = (A { f: 42 },);
+ let o: *const (dyn Trait,) = &p;
+ let r = unsafe {
+ (&*o).0.foo()
+ };
+ assert_eq!(r, 42);
+
+ // raw slice
+ let a: *const [_] = &[1, 2, 3];
+ unsafe {
+ let b = (*a)[2];
+ assert_eq!(b, 3);
+ let len = (*a).len();
+ assert_eq!(len, 3);
+ }
+
+ // raw slice with explicit cast
+ let a = &[1, 2, 3] as *const [i32];
+ unsafe {
+ let b = (*a)[2];
+ assert_eq!(b, 3);
+ let len = (*a).len();
+ assert_eq!(len, 3);
+ }
+
+ // raw DST struct with slice
+ let c: *const Foo<[_]> = &Foo {f: [1, 2, 3]};
+ unsafe {
+ let b = (&*c).f[0];
+ assert_eq!(b, 1);
+ let len = (&*c).f.len();
+ assert_eq!(len, 3);
+ }
+
+ // raw DST tuple with slice
+ let c: *const ([_],) = &([1, 2, 3],);
+ unsafe {
+ let b = (&*c).0[0];
+ assert_eq!(b, 1);
+ let len = (&*c).0.len();
+ assert_eq!(len, 3);
+ }
+
+ // all of the above with *mut
+ let mut x = A { f: 42 };
+ let z: *mut dyn Trait = &mut x;
+ let r = unsafe {
+ (&*z).foo()
+ };
+ assert_eq!(r, 42);
+
+ let mut p = Foo {f: A { f: 42 }};
+ let o: *mut Foo<dyn Trait> = &mut p;
+ let r = unsafe {
+ (&*o).f.foo()
+ };
+ assert_eq!(r, 42);
+
+ let mut p = (A { f: 42 },);
+ let o: *mut (dyn Trait,) = &mut p;
+ let r = unsafe {
+ (&*o).0.foo()
+ };
+ assert_eq!(r, 42);
+
+ let a: *mut [_] = &mut [1, 2, 3];
+ unsafe {
+ let b = (*a)[2];
+ assert_eq!(b, 3);
+ let len = (*a).len();
+ assert_eq!(len, 3);
+ }
+
+ let a = &mut [1, 2, 3] as *mut [i32];
+ unsafe {
+ let b = (*a)[2];
+ assert_eq!(b, 3);
+ let len = (*a).len();
+ assert_eq!(len, 3);
+ }
+
+ let c: *mut Foo<[_]> = &mut Foo {f: [1, 2, 3]};
+ unsafe {
+ let b = (&*c).f[0];
+ assert_eq!(b, 1);
+ let len = (&*c).f.len();
+ assert_eq!(len, 3);
+ }
+
+ let c: *mut ([_],) = &mut ([1, 2, 3],);
+ unsafe {
+ let b = (&*c).0[0];
+ assert_eq!(b, 1);
+ let len = (&*c).0.len();
+ assert_eq!(len, 3);
+ }
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-struct-sole.rs b/src/test/ui/dynamically-sized-types/dst-struct-sole.rs
new file mode 100644
index 000000000..6ca07fcf8
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-struct-sole.rs
@@ -0,0 +1,76 @@
+// run-pass
+// As dst-struct.rs, but the unsized field is the only field in the struct.
+
+
+struct Fat<T: ?Sized> {
+ ptr: T
+}
+
+// x is a fat pointer
+fn foo(x: &Fat<[isize]>) {
+ let y = &x.ptr;
+ assert_eq!(x.ptr.len(), 3);
+ assert_eq!(y[0], 1);
+ assert_eq!(x.ptr[1], 2);
+}
+
+fn foo2<T:ToBar>(x: &Fat<[T]>) {
+ let y = &x.ptr;
+ let bar = Bar;
+ assert_eq!(x.ptr.len(), 3);
+ assert_eq!(y[0].to_bar(), bar);
+ assert_eq!(x.ptr[1].to_bar(), bar);
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+struct Bar;
+
+trait ToBar {
+ fn to_bar(&self) -> Bar;
+}
+
+impl ToBar for Bar {
+ fn to_bar(&self) -> Bar {
+ *self
+ }
+}
+
+pub fn main() {
+ // With a vec of ints.
+ let f1 = Fat { ptr: [1, 2, 3] };
+ foo(&f1);
+ let f2 = &f1;
+ foo(f2);
+ let f3: &Fat<[isize]> = f2;
+ foo(f3);
+ let f4: &Fat<[isize]> = &f1;
+ foo(f4);
+ let f5: &Fat<[isize]> = &Fat { ptr: [1, 2, 3] };
+ foo(f5);
+
+ // With a vec of Bars.
+ let bar = Bar;
+ let f1 = Fat { ptr: [bar, bar, bar] };
+ foo2(&f1);
+ let f2 = &f1;
+ foo2(f2);
+ let f3: &Fat<[Bar]> = f2;
+ foo2(f3);
+ let f4: &Fat<[Bar]> = &f1;
+ foo2(f4);
+ let f5: &Fat<[Bar]> = &Fat { ptr: [bar, bar, bar] };
+ foo2(f5);
+
+ // Assignment.
+ let f5: &mut Fat<[isize]> = &mut Fat { ptr: [1, 2, 3] };
+ f5.ptr[1] = 34;
+ assert_eq!(f5.ptr[0], 1);
+ assert_eq!(f5.ptr[1], 34);
+ assert_eq!(f5.ptr[2], 3);
+
+ // Zero size vec.
+ let f5: &Fat<[isize]> = &Fat { ptr: [] };
+ assert!(f5.ptr.is_empty());
+ let f5: &Fat<[Bar]> = &Fat { ptr: [] };
+ assert!(f5.ptr.is_empty());
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-struct.rs b/src/test/ui/dynamically-sized-types/dst-struct.rs
new file mode 100644
index 000000000..25ec07b88
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-struct.rs
@@ -0,0 +1,122 @@
+// run-pass
+#![feature(box_syntax)]
+
+struct Fat<T: ?Sized> {
+ f1: isize,
+ f2: &'static str,
+ ptr: T
+}
+
+// x is a fat pointer
+fn foo(x: &Fat<[isize]>) {
+ let y = &x.ptr;
+ assert_eq!(x.ptr.len(), 3);
+ assert_eq!(y[0], 1);
+ assert_eq!(x.ptr[1], 2);
+ assert_eq!(x.f1, 5);
+ assert_eq!(x.f2, "some str");
+}
+
+fn foo2<T:ToBar>(x: &Fat<[T]>) {
+ let y = &x.ptr;
+ let bar = Bar;
+ assert_eq!(x.ptr.len(), 3);
+ assert_eq!(y[0].to_bar(), bar);
+ assert_eq!(x.ptr[1].to_bar(), bar);
+ assert_eq!(x.f1, 5);
+ assert_eq!(x.f2, "some str");
+}
+
+fn foo3(x: &Fat<Fat<[isize]>>) {
+ let y = &x.ptr.ptr;
+ assert_eq!(x.f1, 5);
+ assert_eq!(x.f2, "some str");
+ assert_eq!(x.ptr.f1, 8);
+ assert_eq!(x.ptr.f2, "deep str");
+ assert_eq!(x.ptr.ptr.len(), 3);
+ assert_eq!(y[0], 1);
+ assert_eq!(x.ptr.ptr[1], 2);
+}
+
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+struct Bar;
+
+trait ToBar {
+ fn to_bar(&self) -> Bar;
+}
+
+impl ToBar for Bar {
+ fn to_bar(&self) -> Bar {
+ *self
+ }
+}
+
+pub fn main() {
+ // With a vec of ints.
+ let f1 = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] };
+ foo(&f1);
+ let f2 = &f1;
+ foo(f2);
+ let f3: &Fat<[isize]> = f2;
+ foo(f3);
+ let f4: &Fat<[isize]> = &f1;
+ foo(f4);
+ let f5: &Fat<[isize]> = &Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] };
+ foo(f5);
+
+ // With a vec of Bars.
+ let bar = Bar;
+ let f1 = Fat { f1: 5, f2: "some str", ptr: [bar, bar, bar] };
+ foo2(&f1);
+ let f2 = &f1;
+ foo2(f2);
+ let f3: &Fat<[Bar]> = f2;
+ foo2(f3);
+ let f4: &Fat<[Bar]> = &f1;
+ foo2(f4);
+ let f5: &Fat<[Bar]> = &Fat { f1: 5, f2: "some str", ptr: [bar, bar, bar] };
+ foo2(f5);
+
+ // Assignment.
+ let f5: &mut Fat<[isize]> = &mut Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] };
+ f5.ptr[1] = 34;
+ assert_eq!(f5.ptr[0], 1);
+ assert_eq!(f5.ptr[1], 34);
+ assert_eq!(f5.ptr[2], 3);
+
+ // Zero size vec.
+ let f5: &Fat<[isize]> = &Fat { f1: 5, f2: "some str", ptr: [] };
+ assert!(f5.ptr.is_empty());
+ let f5: &Fat<[Bar]> = &Fat { f1: 5, f2: "some str", ptr: [] };
+ assert!(f5.ptr.is_empty());
+
+ // Deeply nested.
+ let f1 = Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} };
+ foo3(&f1);
+ let f2 = &f1;
+ foo3(f2);
+ let f3: &Fat<Fat<[isize]>> = f2;
+ foo3(f3);
+ let f4: &Fat<Fat<[isize]>> = &f1;
+ foo3(f4);
+ let f5: &Fat<Fat<[isize]>> =
+ &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} };
+ foo3(f5);
+
+ // Box.
+ let f1 = Box::new([1, 2, 3]);
+ assert_eq!((*f1)[1], 2);
+ let f2: Box<[isize]> = f1;
+ assert_eq!((*f2)[1], 2);
+
+ // Nested Box.
+ let f1 : Box<Fat<[isize; 3]>> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] };
+ foo(&*f1);
+ let f2 : Box<Fat<[isize]>> = f1;
+ foo(&*f2);
+
+ let f3 : Box<Fat<[isize]>> =
+ Box::<Fat<[_; 3]>>::new(Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] });
+ foo(&*f3);
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-trait-tuple.rs b/src/test/ui/dynamically-sized-types/dst-trait-tuple.rs
new file mode 100644
index 000000000..c1e45215a
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-trait-tuple.rs
@@ -0,0 +1,102 @@
+// run-pass
+#![allow(type_alias_bounds)]
+
+#![allow(unused_features)]
+#![feature(unsized_tuple_coercion)]
+
+type Fat<T: ?Sized> = (isize, &'static str, T);
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+struct Bar;
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+struct Bar1 {
+ f: isize
+}
+
+trait ToBar {
+ fn to_bar(&self) -> Bar;
+ fn to_val(&self) -> isize;
+}
+
+impl ToBar for Bar {
+ fn to_bar(&self) -> Bar {
+ *self
+ }
+ fn to_val(&self) -> isize {
+ 0
+ }
+}
+impl ToBar for Bar1 {
+ fn to_bar(&self) -> Bar {
+ Bar
+ }
+ fn to_val(&self) -> isize {
+ self.f
+ }
+}
+
+// x is a fat pointer
+fn foo(x: &Fat<dyn ToBar>) {
+ assert_eq!(x.0, 5);
+ assert_eq!(x.1, "some str");
+ assert_eq!(x.2.to_bar(), Bar);
+ assert_eq!(x.2.to_val(), 42);
+
+ let y = &x.2;
+ assert_eq!(y.to_bar(), Bar);
+ assert_eq!(y.to_val(), 42);
+}
+
+fn bar(x: &dyn ToBar) {
+ assert_eq!(x.to_bar(), Bar);
+ assert_eq!(x.to_val(), 42);
+}
+
+fn baz(x: &Fat<Fat<dyn ToBar>>) {
+ assert_eq!(x.0, 5);
+ assert_eq!(x.1, "some str");
+ assert_eq!((x.2).0, 8);
+ assert_eq!((x.2).1, "deep str");
+ assert_eq!((x.2).2.to_bar(), Bar);
+ assert_eq!((x.2).2.to_val(), 42);
+
+ let y = &(x.2).2;
+ assert_eq!(y.to_bar(), Bar);
+ assert_eq!(y.to_val(), 42);
+
+}
+
+pub fn main() {
+ let f1 = (5, "some str", Bar1 {f :42});
+ foo(&f1);
+ let f2 = &f1;
+ foo(f2);
+ let f3: &Fat<dyn ToBar> = f2;
+ foo(f3);
+ let f4: &Fat<dyn ToBar> = &f1;
+ foo(f4);
+ let f5: &Fat<dyn ToBar> = &(5, "some str", Bar1 {f :42});
+ foo(f5);
+
+ // Zero size object.
+ let f6: &Fat<dyn ToBar> = &(5, "some str", Bar);
+ assert_eq!(f6.2.to_bar(), Bar);
+
+ // &*
+ //
+ let f7: Box<dyn ToBar> = Box::new(Bar1 {f :42});
+ bar(&*f7);
+
+ // Deep nesting
+ let f1 = (5, "some str", (8, "deep str", Bar1 {f :42}));
+ baz(&f1);
+ let f2 = &f1;
+ baz(f2);
+ let f3: &Fat<Fat<dyn ToBar>> = f2;
+ baz(f3);
+ let f4: &Fat<Fat<dyn ToBar>> = &f1;
+ baz(f4);
+ let f5: &Fat<Fat<dyn ToBar>> = &(5, "some str", (8, "deep str", Bar1 {f :42}));
+ baz(f5);
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-trait.rs b/src/test/ui/dynamically-sized-types/dst-trait.rs
new file mode 100644
index 000000000..ec6bc7219
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-trait.rs
@@ -0,0 +1,105 @@
+// run-pass
+#![feature(box_syntax)]
+
+struct Fat<T: ?Sized> {
+ f1: isize,
+ f2: &'static str,
+ ptr: T
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+struct Bar;
+
+#[derive(Copy, Clone, PartialEq, Eq)]
+struct Bar1 {
+ f: isize
+}
+
+trait ToBar {
+ fn to_bar(&self) -> Bar;
+ fn to_val(&self) -> isize;
+}
+
+impl ToBar for Bar {
+ fn to_bar(&self) -> Bar {
+ *self
+ }
+ fn to_val(&self) -> isize {
+ 0
+ }
+}
+impl ToBar for Bar1 {
+ fn to_bar(&self) -> Bar {
+ Bar
+ }
+ fn to_val(&self) -> isize {
+ self.f
+ }
+}
+
+// x is a fat pointer
+fn foo(x: &Fat<dyn ToBar>) {
+ assert_eq!(x.f1, 5);
+ assert_eq!(x.f2, "some str");
+ assert_eq!(x.ptr.to_bar(), Bar);
+ assert_eq!(x.ptr.to_val(), 42);
+
+ let y = &x.ptr;
+ assert_eq!(y.to_bar(), Bar);
+ assert_eq!(y.to_val(), 42);
+}
+
+fn bar(x: &dyn ToBar) {
+ assert_eq!(x.to_bar(), Bar);
+ assert_eq!(x.to_val(), 42);
+}
+
+fn baz(x: &Fat<Fat<dyn ToBar>>) {
+ assert_eq!(x.f1, 5);
+ assert_eq!(x.f2, "some str");
+ assert_eq!(x.ptr.f1, 8);
+ assert_eq!(x.ptr.f2, "deep str");
+ assert_eq!(x.ptr.ptr.to_bar(), Bar);
+ assert_eq!(x.ptr.ptr.to_val(), 42);
+
+ let y = &x.ptr.ptr;
+ assert_eq!(y.to_bar(), Bar);
+ assert_eq!(y.to_val(), 42);
+
+}
+
+pub fn main() {
+ let f1 = Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} };
+ foo(&f1);
+ let f2 = &f1;
+ foo(f2);
+ let f3: &Fat<dyn ToBar> = f2;
+ foo(f3);
+ let f4: &Fat<dyn ToBar> = &f1;
+ foo(f4);
+ let f5: &Fat<dyn ToBar> = &Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} };
+ foo(f5);
+
+ // Zero size object.
+ let f6: &Fat<dyn ToBar> = &Fat { f1: 5, f2: "some str", ptr: Bar };
+ assert_eq!(f6.ptr.to_bar(), Bar);
+
+ // &*
+ //
+ let f7: Box<dyn ToBar> = Box::new(Bar1 {f :42});
+ bar(&*f7);
+
+ // Deep nesting
+ let f1 =
+ Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: Bar1 {f :42}} };
+ baz(&f1);
+ let f2 = &f1;
+ baz(f2);
+ let f3: &Fat<Fat<dyn ToBar>> = f2;
+ baz(f3);
+ let f4: &Fat<Fat<dyn ToBar>> = &f1;
+ baz(f4);
+ let f5: &Fat<Fat<dyn ToBar>> =
+ &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: Bar1 {f :42}} };
+ baz(f5);
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs b/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs
new file mode 100644
index 000000000..26b923f43
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs
@@ -0,0 +1,26 @@
+// run-pass
+
+#![feature(unsized_tuple_coercion)]
+
+// Ensure that unsizable fields that might be accessed don't get reordered
+
+fn nonzero_size() {
+ let sized: (u8, [u32; 2]) = (123, [456, 789]);
+ let unsize: &(u8, [u32]) = &sized;
+ assert_eq!(unsize.0, 123);
+ assert_eq!(unsize.1.len(), 2);
+ assert_eq!(unsize.1[0], 456);
+ assert_eq!(unsize.1[1], 789);
+}
+
+fn zst() {
+ let sized: (u8, [u32; 0]) = (123, []);
+ let unsize: &(u8, [u32]) = &sized;
+ assert_eq!(unsize.0, 123);
+ assert_eq!(unsize.1.len(), 0);
+}
+
+pub fn main() {
+ nonzero_size();
+ zst();
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-tuple-sole.rs b/src/test/ui/dynamically-sized-types/dst-tuple-sole.rs
new file mode 100644
index 000000000..606689da0
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-tuple-sole.rs
@@ -0,0 +1,79 @@
+// run-pass
+#![allow(stable_features)]
+#![allow(type_alias_bounds)]
+
+// As dst-tuple.rs, but the unsized field is the only field in the tuple.
+
+
+#![feature(unsized_tuple_coercion)]
+
+type Fat<T: ?Sized> = (T,);
+
+// x is a fat pointer
+fn foo(x: &Fat<[isize]>) {
+ let y = &x.0;
+ assert_eq!(x.0.len(), 3);
+ assert_eq!(y[0], 1);
+ assert_eq!(x.0[1], 2);
+}
+
+fn foo2<T:ToBar>(x: &Fat<[T]>) {
+ let y = &x.0;
+ let bar = Bar;
+ assert_eq!(x.0.len(), 3);
+ assert_eq!(y[0].to_bar(), bar);
+ assert_eq!(x.0[1].to_bar(), bar);
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+struct Bar;
+
+trait ToBar {
+ fn to_bar(&self) -> Bar;
+}
+
+impl ToBar for Bar {
+ fn to_bar(&self) -> Bar {
+ *self
+ }
+}
+
+pub fn main() {
+ // With a vec of ints.
+ let f1 = ([1, 2, 3],);
+ foo(&f1);
+ let f2 = &f1;
+ foo(f2);
+ let f3: &Fat<[isize]> = f2;
+ foo(f3);
+ let f4: &Fat<[isize]> = &f1;
+ foo(f4);
+ let f5: &Fat<[isize]> = &([1, 2, 3],);
+ foo(f5);
+
+ // With a vec of Bars.
+ let bar = Bar;
+ let f1 = ([bar, bar, bar],);
+ foo2(&f1);
+ let f2 = &f1;
+ foo2(f2);
+ let f3: &Fat<[Bar]> = f2;
+ foo2(f3);
+ let f4: &Fat<[Bar]> = &f1;
+ foo2(f4);
+ let f5: &Fat<[Bar]> = &([bar, bar, bar],);
+ foo2(f5);
+
+ // Assignment.
+ let f5: &mut Fat<[isize]> = &mut ([1, 2, 3],);
+ f5.0[1] = 34;
+ assert_eq!(f5.0[0], 1);
+ assert_eq!(f5.0[1], 34);
+ assert_eq!(f5.0[2], 3);
+
+ // Zero size vec.
+ let f5: &Fat<[isize]> = &([],);
+ assert!(f5.0.is_empty());
+ let f5: &Fat<[Bar]> = &([],);
+ assert!(f5.0.is_empty());
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs b/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs
new file mode 100644
index 000000000..b0cefe770
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs
@@ -0,0 +1,22 @@
+// run-pass
+
+#![feature(unsized_tuple_coercion)]
+
+// Check that we do not change the offsets of ZST fields when unsizing
+
+fn scalar_layout() {
+ let sized: &(u8, [(); 13]) = &(123, [(); 13]);
+ let unsize: &(u8, [()]) = sized;
+ assert_eq!(sized.1.as_ptr(), unsize.1.as_ptr());
+}
+
+fn scalarpair_layout() {
+ let sized: &(u8, u16, [(); 13]) = &(123, 456, [(); 13]);
+ let unsize: &(u8, u16, [()]) = sized;
+ assert_eq!(sized.2.as_ptr(), unsize.2.as_ptr());
+}
+
+pub fn main() {
+ scalar_layout();
+ scalarpair_layout();
+}
diff --git a/src/test/ui/dynamically-sized-types/dst-tuple.rs b/src/test/ui/dynamically-sized-types/dst-tuple.rs
new file mode 100644
index 000000000..604ac5112
--- /dev/null
+++ b/src/test/ui/dynamically-sized-types/dst-tuple.rs
@@ -0,0 +1,119 @@
+// run-pass
+#![allow(type_alias_bounds)]
+
+#![feature(unsized_tuple_coercion)]
+
+type Fat<T: ?Sized> = (isize, &'static str, T);
+
+// x is a fat pointer
+fn foo(x: &Fat<[isize]>) {
+ let y = &x.2;
+ assert_eq!(x.2.len(), 3);
+ assert_eq!(y[0], 1);
+ assert_eq!(x.2[1], 2);
+ assert_eq!(x.0, 5);
+ assert_eq!(x.1, "some str");
+}
+
+fn foo2<T:ToBar>(x: &Fat<[T]>) {
+ let y = &x.2;
+ let bar = Bar;
+ assert_eq!(x.2.len(), 3);
+ assert_eq!(y[0].to_bar(), bar);
+ assert_eq!(x.2[1].to_bar(), bar);
+ assert_eq!(x.0, 5);
+ assert_eq!(x.1, "some str");
+}
+
+fn foo3(x: &Fat<Fat<[isize]>>) {
+ let y = &(x.2).2;
+ assert_eq!(x.0, 5);
+ assert_eq!(x.1, "some str");
+ assert_eq!((x.2).0, 8);
+ assert_eq!((x.2).1, "deep str");
+ assert_eq!((x.2).2.len(), 3);
+ assert_eq!(y[0], 1);
+ assert_eq!((x.2).2[1], 2);
+}
+
+
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+struct Bar;
+
+trait ToBar {
+ fn to_bar(&self) -> Bar;
+}
+
+impl ToBar for Bar {
+ fn to_bar(&self) -> Bar {
+ *self
+ }
+}
+
+pub fn main() {
+ // With a vec of ints.
+ let f1 = (5, "some str", [1, 2, 3]);
+ foo(&f1);
+ let f2 = &f1;
+ foo(f2);
+ let f3: &Fat<[isize]> = f2;
+ foo(f3);
+ let f4: &Fat<[isize]> = &f1;
+ foo(f4);
+ let f5: &Fat<[isize]> = &(5, "some str", [1, 2, 3]);
+ foo(f5);
+
+ // With a vec of Bars.
+ let bar = Bar;
+ let f1 = (5, "some str", [bar, bar, bar]);
+ foo2(&f1);
+ let f2 = &f1;
+ foo2(f2);
+ let f3: &Fat<[Bar]> = f2;
+ foo2(f3);
+ let f4: &Fat<[Bar]> = &f1;
+ foo2(f4);
+ let f5: &Fat<[Bar]> = &(5, "some str", [bar, bar, bar]);
+ foo2(f5);
+
+ // Assignment.
+ let f5: &mut Fat<[isize]> = &mut (5, "some str", [1, 2, 3]);
+ f5.2[1] = 34;
+ assert_eq!(f5.2[0], 1);
+ assert_eq!(f5.2[1], 34);
+ assert_eq!(f5.2[2], 3);
+
+ // Zero size vec.
+ let f5: &Fat<[isize]> = &(5, "some str", []);
+ assert!(f5.2.is_empty());
+ let f5: &Fat<[Bar]> = &(5, "some str", []);
+ assert!(f5.2.is_empty());
+
+ // Deeply nested.
+ let f1 = (5, "some str", (8, "deep str", [1, 2, 3]));
+ foo3(&f1);
+ let f2 = &f1;
+ foo3(f2);
+ let f3: &Fat<Fat<[isize]>> = f2;
+ foo3(f3);
+ let f4: &Fat<Fat<[isize]>> = &f1;
+ foo3(f4);
+ let f5: &Fat<Fat<[isize]>> = &(5, "some str", (8, "deep str", [1, 2, 3]));
+ foo3(f5);
+
+ // Box.
+ let f1 = Box::new([1, 2, 3]);
+ assert_eq!((*f1)[1], 2);
+ let f2: Box<[isize]> = f1;
+ assert_eq!((*f2)[1], 2);
+
+ // Nested Box.
+ let f1 : Box<Fat<[isize; 3]>> = Box::new((5, "some str", [1, 2, 3]));
+ foo(&*f1);
+ let f2 : Box<Fat<[isize]>> = f1;
+ foo(&*f2);
+
+ let f3 : Box<Fat<[isize]>> =
+ Box::<Fat<[_; 3]>>::new((5, "some str", [1, 2, 3]));
+ foo(&*f3);
+}