Auto merge of #54183 - qnighy:by-value-object-safety, r=oli-obk

Implement by-value object safety

This PR implements **by-value object safety**, which is part of unsized rvalues #48055. That means, with `#![feature(unsized_locals)]`, you can call a method `fn foo(self, ...)` on trait objects. One aim of this is to enable `Box<FnOnce>`  in the near future.

The difficulty here is this: when constructing a vtable for a trait `Foo`, we can't just put the function `<T as Foo>::foo` into the table. If `T` is no larger than `usize`, `self` is usually passed directly. However, as the caller of the vtable doesn't know the concrete `Self` type, we want a variant of `<T as Foo>::foo` where `self` is always passed by reference.

Therefore, when the compiler encounters such a method to be generated as a vtable entry, it produces a newly introduced instance called `InstanceDef::VtableShim(def_id)` (that wraps the original instance). the shim just derefs the receiver and calls the original method. We give different symbol names for the shims by appending `::{{vtable-shim}}` to the symbol path (and also adding vtable-shimness as an ingredient to the symbol hash).

r? @eddyb
This commit is contained in:
bors 2018-10-27 19:29:35 +00:00
commit cae6efc37d
46 changed files with 870 additions and 171 deletions

View file

@ -0,0 +1,55 @@
#![feature(unsized_locals)]
#![feature(unboxed_closures)]
pub trait FnOnce<Args> {
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
struct A;
impl FnOnce<()> for A {
type Output = String;
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
format!("hello")
}
}
struct B(i32);
impl FnOnce<()> for B {
type Output = String;
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
format!("{}", self.0)
}
}
struct C(String);
impl FnOnce<()> for C {
type Output = String;
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
self.0
}
}
struct D(Box<String>);
impl FnOnce<()> for D {
type Output = String;
extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
*self.0
}
}
fn main() {
let x = *(Box::new(A) as Box<dyn FnOnce<(), Output = String>>);
assert_eq!(x.call_once(()), format!("hello"));
let x = *(Box::new(B(42)) as Box<dyn FnOnce<(), Output = String>>);
assert_eq!(x.call_once(()), format!("42"));
let x = *(Box::new(C(format!("jumping fox"))) as Box<dyn FnOnce<(), Output = String>>);
assert_eq!(x.call_once(()), format!("jumping fox"));
let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box<dyn FnOnce<(), Output = String>>);
assert_eq!(x.call_once(()), format!("lazy dog"));
}

View file

@ -0,0 +1,69 @@
#![feature(unsized_locals)]
#![feature(unboxed_closures)]
pub trait FnOnce<Args> {
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
struct A;
impl FnOnce<(String, Box<str>)> for A {
type Output = String;
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
assert_eq!(&s1 as &str, "s1");
assert_eq!(&s2 as &str, "s2");
format!("hello")
}
}
struct B(i32);
impl FnOnce<(String, Box<str>)> for B {
type Output = String;
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
assert_eq!(&s1 as &str, "s1");
assert_eq!(&s2 as &str, "s2");
format!("{}", self.0)
}
}
struct C(String);
impl FnOnce<(String, Box<str>)> for C {
type Output = String;
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
assert_eq!(&s1 as &str, "s1");
assert_eq!(&s2 as &str, "s2");
self.0
}
}
struct D(Box<String>);
impl FnOnce<(String, Box<str>)> for D {
type Output = String;
extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
assert_eq!(&s1 as &str, "s1");
assert_eq!(&s2 as &str, "s2");
*self.0
}
}
fn main() {
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
let x = *(Box::new(A) as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
assert_eq!(x.call_once((s1, s2)), format!("hello"));
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
let x = *(Box::new(B(42)) as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
assert_eq!(x.call_once((s1, s2)), format!("42"));
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
let x = *(Box::new(C(format!("jumping fox")))
as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
assert_eq!(x.call_once((s1, s2)), format!("jumping fox"));
let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
let x = *(Box::new(D(Box::new(format!("lazy dog"))))
as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
assert_eq!(x.call_once((s1, s2)), format!("lazy dog"));
}

View file

@ -0,0 +1,49 @@
#![feature(unsized_locals)]
pub trait Foo {
fn foo(self) -> String;
}
struct A;
impl Foo for A {
fn foo(self) -> String {
format!("hello")
}
}
struct B(i32);
impl Foo for B {
fn foo(self) -> String {
format!("{}", self.0)
}
}
struct C(String);
impl Foo for C {
fn foo(self) -> String {
self.0
}
}
struct D(Box<String>);
impl Foo for D {
fn foo(self) -> String {
*self.0
}
}
fn main() {
let x = *(Box::new(A) as Box<dyn Foo>);
assert_eq!(x.foo(), format!("hello"));
let x = *(Box::new(B(42)) as Box<dyn Foo>);
assert_eq!(x.foo(), format!("42"));
let x = *(Box::new(C(format!("jumping fox"))) as Box<dyn Foo>);
assert_eq!(x.foo(), format!("jumping fox"));
let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box<dyn Foo>);
assert_eq!(x.foo(), format!("lazy dog"));
}

View file

@ -1,13 +1,3 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unsized_locals)]
use std::fmt;

View file

@ -0,0 +1,47 @@
#![feature(unsized_locals)]
pub trait Foo {
fn foo(self) -> String;
}
impl Foo for [char] {
fn foo(self) -> String {
self.iter().collect()
}
}
impl Foo for str {
fn foo(self) -> String {
self.to_owned()
}
}
impl Foo for dyn FnMut() -> String {
fn foo(mut self) -> String {
self()
}
}
fn main() {
let x = *(Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>);
assert_eq!(&x.foo() as &str, "hello");
let x = Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>;
assert_eq!(&x.foo() as &str, "hello");
let x = "hello".to_owned().into_boxed_str();
assert_eq!(&x.foo() as &str, "hello");
let x = *("hello".to_owned().into_boxed_str());
assert_eq!(&x.foo() as &str, "hello");
let x = "hello".to_owned().into_boxed_str();
assert_eq!(&x.foo() as &str, "hello");
let x = *(Box::new(|| "hello".to_owned()) as Box<dyn FnMut() -> String>);
assert_eq!(&x.foo() as &str, "hello");
let x = Box::new(|| "hello".to_owned()) as Box<dyn FnMut() -> String>;
assert_eq!(&x.foo() as &str, "hello");
}

View file

@ -0,0 +1,21 @@
#![feature(unsized_locals)]
pub trait Foo {
fn foo(self) -> String {
format!("hello")
}
}
struct A;
impl Foo for A {}
fn main() {
let x = *(Box::new(A) as Box<dyn Foo>);
assert_eq!(x.foo(), format!("hello"));
// I'm not sure whether we want this to work
let x = Box::new(A) as Box<dyn Foo>;
assert_eq!(x.foo(), format!("hello"));
}

View file

@ -0,0 +1,23 @@
#![feature(unsized_locals)]
pub trait Foo {
fn foo(self) -> String;
}
struct A;
impl Foo for A {
fn foo(self) -> String {
format!("hello")
}
}
fn main() {
let x = *(Box::new(A) as Box<dyn Foo>);
assert_eq!(x.foo(), format!("hello"));
// I'm not sure whether we want this to work
let x = Box::new(A) as Box<dyn Foo>;
assert_eq!(x.foo(), format!("hello"));
}

View file

@ -1,13 +1,3 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-pass
#![feature(unsized_locals)]

View file

@ -1,13 +1,3 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-pass
#![feature(unsized_locals)]

View file

@ -1,13 +1,3 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-pass
#![feature(unsized_tuple_coercion, unsized_locals)]

View file

@ -1,13 +1,3 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// run-pass
#![feature(unsized_locals)]

View file

@ -1,4 +1,4 @@
error: symbol-name(_ZN5basic4main17h2138d548fb9814b6E)
error: symbol-name(_ZN5basic4main17h08bcaf310214ed52E)
--> $DIR/basic.rs:13:1
|
LL | #[rustc_symbol_name] //~ ERROR _ZN5basic4main

View file

@ -1,4 +1,4 @@
error: symbol-name(_ZN5impl13foo3Foo3bar17h8da62e6147ff602fE)
error: symbol-name(_ZN5impl13foo3Foo3bar17hc487d6ec13fe9124E)
--> $DIR/impl1.rs:18:9
|
LL | #[rustc_symbol_name] //~ ERROR _ZN5impl13foo3Foo3bar
@ -10,7 +10,7 @@ error: item-path(foo::Foo::bar)
LL | #[rustc_item_path] //~ ERROR item-path(foo::Foo::bar)
| ^^^^^^^^^^^^^^^^^^
error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h374cb8f6185db9b4E)
error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h38577281258e1527E)
--> $DIR/impl1.rs:28:9
|
LL | #[rustc_symbol_name] //~ ERROR _ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz

View file

@ -0,0 +1,51 @@
error[E0382]: borrow of moved value: `x`
--> $DIR/borrow-after-move.rs:20:24
|
LL | let y = *x;
| -- value moved here
LL | drop_unsized(y);
LL | println!("{}", &x);
| ^^ value borrowed here after move
error[E0382]: borrow of moved value: `y`
--> $DIR/borrow-after-move.rs:22:24
|
LL | drop_unsized(y);
| - value moved here
...
LL | println!("{}", &y);
| ^^ value borrowed here after move
|
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/borrow-after-move.rs:30:24
|
LL | let y = *x;
| -- value moved here
LL | y.foo();
LL | println!("{}", &x);
| ^^ value borrowed here after move
error[E0382]: borrow of moved value: `y`
--> $DIR/borrow-after-move.rs:32:24
|
LL | y.foo();
| - value moved here
...
LL | println!("{}", &y);
| ^^ value borrowed here after move
|
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: borrow of moved value: `x`
--> $DIR/borrow-after-move.rs:39:24
|
LL | x.foo();
| - value moved here
LL | println!("{}", &x);
| ^^ value borrowed here after move
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0382`.

View file

@ -0,0 +1,42 @@
#![feature(unsized_locals)]
pub trait Foo {
fn foo(self) -> String;
}
impl Foo for str {
fn foo(self) -> String {
self.to_owned()
}
}
fn drop_unsized<T: ?Sized>(_: T) {}
fn main() {
{
let x = "hello".to_owned().into_boxed_str();
let y = *x;
drop_unsized(y);
println!("{}", &x);
//~^ERROR use of moved value
println!("{}", &y);
//~^ERROR use of moved value
}
{
let x = "hello".to_owned().into_boxed_str();
let y = *x;
y.foo();
println!("{}", &x);
//~^ERROR use of moved value
println!("{}", &y);
//~^ERROR use of moved value
}
{
let x = "hello".to_owned().into_boxed_str();
x.foo();
println!("{}", &x);
//~^ERROR use of moved value
}
}

View file

@ -0,0 +1,57 @@
error[E0382]: use of moved value: `x`
--> $DIR/borrow-after-move.rs:20:25
|
LL | let y = *x;
| - value moved here
LL | drop_unsized(y);
LL | println!("{}", &x);
| ^ value used here after move
|
= note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `y`
--> $DIR/borrow-after-move.rs:22:25
|
LL | drop_unsized(y);
| - value moved here
...
LL | println!("{}", &y);
| ^ value used here after move
|
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `x`
--> $DIR/borrow-after-move.rs:30:25
|
LL | let y = *x;
| - value moved here
LL | y.foo();
LL | println!("{}", &x);
| ^ value used here after move
|
= note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `y`
--> $DIR/borrow-after-move.rs:32:25
|
LL | y.foo();
| - value moved here
...
LL | println!("{}", &y);
| ^ value used here after move
|
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `x`
--> $DIR/borrow-after-move.rs:39:25
|
LL | x.foo();
| - value moved here
LL | println!("{}", &x);
| ^ value used here after move
|
= note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0382`.

View file

@ -0,0 +1,20 @@
#![feature(unsized_locals)]
pub trait Foo {
fn foo(self) -> String where Self: Sized;
}
struct A;
impl Foo for A {
fn foo(self) -> String {
format!("hello")
}
}
fn main() {
let x = *(Box::new(A) as Box<dyn Foo>);
x.foo();
//~^ERROR the `foo` method cannot be invoked on a trait object
}

View file

@ -0,0 +1,8 @@
error: the `foo` method cannot be invoked on a trait object
--> $DIR/by-value-trait-object-safety.rs:18:7
|
LL | x.foo();
| ^^^
error: aborting due to previous error

View file

@ -0,0 +1,55 @@
error[E0382]: use of moved value: `y`
--> $DIR/double-move.rs:20:22
|
LL | drop_unsized(y);
| - value moved here
LL | drop_unsized(y); //~ERROR use of moved value
| ^ value used here after move
|
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `x`
--> $DIR/double-move.rs:26:22
|
LL | let _y = *x;
| -- value moved here
LL | drop_unsized(x); //~ERROR use of moved value
| ^ value used here after move
error[E0382]: use of moved value: `*x`
--> $DIR/double-move.rs:32:18
|
LL | drop_unsized(x);
| - value moved here
LL | let _y = *x; //~ERROR use of moved value
| ^^ value used here after move
error[E0382]: use of moved value: `y`
--> $DIR/double-move.rs:39:9
|
LL | y.foo();
| - value moved here
LL | y.foo(); //~ERROR use of moved value
| ^ value used here after move
|
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `*x`
--> $DIR/double-move.rs:45:9
|
LL | let _y = *x;
| -- value moved here
LL | x.foo(); //~ERROR use of moved value
| ^ value used here after move
error[E0382]: use of moved value: `*x`
--> $DIR/double-move.rs:51:18
|
LL | x.foo();
| - value moved here
LL | let _y = *x; //~ERROR use of moved value
| ^^ value used here after move
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0382`.

View file

@ -0,0 +1,53 @@
#![feature(unsized_locals)]
pub trait Foo {
fn foo(self) -> String;
}
impl Foo for str {
fn foo(self) -> String {
self.to_owned()
}
}
fn drop_unsized<T: ?Sized>(_: T) {}
fn main() {
{
let x = "hello".to_owned().into_boxed_str();
let y = *x;
drop_unsized(y);
drop_unsized(y); //~ERROR use of moved value
}
{
let x = "hello".to_owned().into_boxed_str();
let _y = *x;
drop_unsized(x); //~ERROR use of moved value
}
{
let x = "hello".to_owned().into_boxed_str();
drop_unsized(x);
let _y = *x; //~ERROR use of moved value
}
{
let x = "hello".to_owned().into_boxed_str();
let y = *x;
y.foo();
y.foo(); //~ERROR use of moved value
}
{
let x = "hello".to_owned().into_boxed_str();
let _y = *x;
x.foo(); //~ERROR use of moved value
}
{
let x = "hello".to_owned().into_boxed_str();
x.foo();
let _y = *x; //~ERROR use of moved value
}
}

View file

@ -0,0 +1,63 @@
error[E0382]: use of moved value: `y`
--> $DIR/double-move.rs:20:22
|
LL | drop_unsized(y);
| - value moved here
LL | drop_unsized(y); //~ERROR use of moved value
| ^ value used here after move
|
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `x`
--> $DIR/double-move.rs:26:22
|
LL | let _y = *x;
| -- value moved here
LL | drop_unsized(x); //~ERROR use of moved value
| ^ value used here after move
|
= note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `*x`
--> $DIR/double-move.rs:32:13
|
LL | drop_unsized(x);
| - value moved here
LL | let _y = *x; //~ERROR use of moved value
| ^^ value used here after move
|
= note: move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `y`
--> $DIR/double-move.rs:39:9
|
LL | y.foo();
| - value moved here
LL | y.foo(); //~ERROR use of moved value
| ^ value used here after move
|
= note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `*x`
--> $DIR/double-move.rs:45:9
|
LL | let _y = *x;
| -- value moved here
LL | x.foo(); //~ERROR use of moved value
| ^ value used here after move
|
= note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `*x`
--> $DIR/double-move.rs:51:13
|
LL | x.foo();
| - value moved here
LL | let _y = *x; //~ERROR use of moved value
| ^^ value used here after move
|
= note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0382`.

View file

@ -1,13 +1,3 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unsized_tuple_coercion, unsized_locals)]
struct A<X: ?Sized>(X);

View file

@ -0,0 +1,25 @@
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/unsized-exprs.rs:22:26
|
LL | udrop::<(i32, [u8])>((42, *foo()));
| ^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: within `({integer}, [u8])`, the trait `std::marker::Sized` is not implemented for `[u8]`
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required because it appears within the type `({integer}, [u8])`
= note: tuples must have a statically known size to be initialized
error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
--> $DIR/unsized-exprs.rs:24:22
|
LL | udrop::<A<[u8]>>(A { 0: *foo() });
| ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
|
= help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]`
= note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
= note: required because it appears within the type `A<[u8]>`
= note: structs must have a statically known size to be initialized
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,19 @@
error[E0508]: cannot move out of type `[u8]`, a non-copy slice
--> $DIR/unsized-exprs2.rs:22:19
|
LL | udrop::<[u8]>(foo()[..]);
| ^^^^^^^^^ cannot move out of here
error[E0507]: cannot move out of data in a `&` reference
--> $DIR/unsized-exprs2.rs:22:19
|
LL | udrop::<[u8]>(foo()[..]);
| ^^^^^^^^^
| |
| cannot move out of data in a `&` reference
| cannot move
error: aborting due to 2 previous errors
Some errors occurred: E0507, E0508.
For more information about an error, try `rustc --explain E0507`.

View file

@ -1,13 +1,3 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(unsized_tuple_coercion, unsized_locals)]
struct A<X: ?Sized>(X);

View file

@ -0,0 +1,9 @@
error[E0507]: cannot move out of indexed content
--> $DIR/unsized-exprs2.rs:22:19
|
LL | udrop::<[u8]>(foo()[..]);
| ^^^^^^^^^ cannot move out of indexed content
error: aborting due to previous error
For more information about this error, try `rustc --explain E0507`.