From d490c34086cbb91f5258f72a6a98e813bc2c9ce1 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 20 Dec 2019 23:11:41 +0000 Subject: [PATCH 1/2] Don't ICE in subslice pattern const-eval --- src/librustc_mir/interpret/operand.rs | 18 ++++++++++++++++-- src/librustc_mir/interpret/place.rs | 11 +++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 48e7193ec39d4..93ab7b9aab7fb 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -444,13 +444,27 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Field(field, _) => self.operand_field(base, field.index() as u64)?, Downcast(_, variant) => self.operand_downcast(base, variant)?, Deref => self.deref_operand(base)?.into(), - Subslice { .. } | ConstantIndex { .. } | Index(_) => if base.layout.is_zst() { + ConstantIndex { .. } | Index(_) if base.layout.is_zst() => { OpTy { op: Operand::Immediate(Scalar::zst().into()), // the actual index doesn't matter, so we just pick a convenient one like 0 layout: base.layout.field(self, 0)?, } - } else { + } + Subslice { from, to, from_end } if base.layout.is_zst() => { + let elem_ty = if let ty::Array(elem_ty, _) = base.layout.ty.kind { + elem_ty + } else { + bug!("slices shouldn't be zero-sized"); + }; + assert!(!from_end, "arrays shouldn't be subsliced from the end"); + + OpTy { + op: Operand::Immediate(Scalar::zst().into()), + layout: self.layout_of(self.tcx.mk_array(elem_ty, (to - from) as u64))?, + } + } + Subslice { .. } | ConstantIndex { .. } | Index(_) => { // The rest should only occur as mplace, we do not use Immediates for types // allowing such operations. This matches place_projection forcing an allocation. let mplace = base.assert_mem_place(); diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 42fbfeca3f05d..8923b167fdee8 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -455,7 +455,10 @@ where ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { let len = base.len(self)?; // also asserts that we have a type where this makes sense let actual_to = if from_end { - assert!(from <= len - to); + if from + to > len { + // This can only be reached in ConstProp and non-rustc-MIR. + throw_ub!(BoundsCheckFailed { len: len as u64, index: from as u64 + to as u64 }); + } len - to } else { to @@ -523,7 +526,11 @@ where from_end, } => { let n = base.len(self)?; - assert!(n >= min_length as u64); + if n < min_length as u64 { + // This can only be reached in ConstProp and non-rustc-MIR. + throw_ub!(BoundsCheckFailed { len: min_length as u64, index: n as u64 }); + } + assert!(offset < min_length); let index = if from_end { n - u64::from(offset) From 8c3c4466483af5f51b49148c64844ea0d31b59da Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 15 Dec 2019 16:14:24 +0000 Subject: [PATCH 2/2] Add more tests for slice patterns --- .../subslice-patterns-const-eval-match.rs | 97 ++++++++++++++ .../subslice-patterns-const-eval.rs | 97 ++++++++++++++ .../borrowck-closures-slice-patterns-ok.rs | 118 ++++++++++++++++++ .../borrowck-closures-slice-patterns.rs | 84 +++++++++++++ .../borrowck-closures-slice-patterns.stderr | 114 +++++++++++++++++ src/test/ui/moves/move-out-of-array-ref.rs | 36 ++++++ .../ui/moves/move-out-of-array-ref.stderr | 47 +++++++ src/test/ui/moves/move-out-of-slice-2.rs | 34 +++++ src/test/ui/moves/move-out-of-slice-2.stderr | 51 ++++++++ 9 files changed, 678 insertions(+) create mode 100644 src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs create mode 100644 src/test/ui/array-slice-vec/subslice-patterns-const-eval.rs create mode 100644 src/test/ui/borrowck/borrowck-closures-slice-patterns-ok.rs create mode 100644 src/test/ui/borrowck/borrowck-closures-slice-patterns.rs create mode 100644 src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr create mode 100644 src/test/ui/moves/move-out-of-array-ref.rs create mode 100644 src/test/ui/moves/move-out-of-array-ref.stderr create mode 100644 src/test/ui/moves/move-out-of-slice-2.rs create mode 100644 src/test/ui/moves/move-out-of-slice-2.stderr diff --git a/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs b/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs new file mode 100644 index 0000000000000..0e767d9613a99 --- /dev/null +++ b/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs @@ -0,0 +1,97 @@ +// Test that slice subslice patterns are correctly handled in const evaluation. + +// run-pass + +#![feature(slice_patterns, const_fn, const_if_match)] +#[derive(PartialEq, Debug, Clone)] +struct N(u8); + +#[derive(PartialEq, Debug, Clone)] +struct Z; + +macro_rules! n { + ($($e:expr),* $(,)?) => { + [$(N($e)),*] + } +} + +// This macro has an unused variable so that it can be repeated base on the +// number of times a repeated variable (`$e` in `z`) occurs. +macro_rules! zed { + ($e:expr) => { Z } +} + +macro_rules! z { + ($($e:expr),* $(,)?) => { + [$(zed!($e)),*] + } +} + +// Compare constant evaluation and runtime evaluation of a given expression. +macro_rules! compare_evaluation_inner { + ($e:expr, $t:ty $(,)?) => {{ + const CONST_EVAL: $t = $e; + const fn const_eval() -> $t { $e } + static CONST_EVAL2: $t = const_eval(); + let runtime_eval = $e; + assert_eq!(CONST_EVAL, runtime_eval); + assert_eq!(CONST_EVAL2, runtime_eval); + }} +} + +// Compare the result of matching `$e` against `$p` using both `if let` and +// `match`. +macro_rules! compare_evaluation { + ($p:pat, $e:expr, $matches:expr, $t:ty $(,)?) => {{ + compare_evaluation_inner!(if let $p = $e as &[_] { $matches } else { None }, $t); + compare_evaluation_inner!(match $e as &[_] { $p => $matches, _ => None }, $t); + }} +} + +// Repeat `$test`, substituting the given macro variables with the given +// identifiers. +// +// For example: +// +// repeat! { +// ($name); X; Y: +// struct $name; +// } +// +// Expands to: +// +// struct X; struct Y; +// +// This is used to repeat the tests using both the `N` and `Z` +// types. +macro_rules! repeat { + (($($dollar:tt $placeholder:ident)*); $($($values:ident),+);*: $($test:tt)*) => { + macro_rules! single { + ($($dollar $placeholder:ident),*) => { $($test)* } + } + $(single!($($values),+);)* + } +} + +fn main() { + repeat! { + ($arr $Ty); n, N; z, Z: + compare_evaluation!([_, x @ .., _], &$arr!(1, 2, 3, 4), Some(x), Option<&'static [$Ty]>); + compare_evaluation!([x, .., _], &$arr!(1, 2, 3, 4), Some(x), Option<&'static $Ty>); + compare_evaluation!([_, .., x], &$arr!(1, 2, 3, 4), Some(x), Option<&'static $Ty>); + + compare_evaluation!([_, x @ .., _], &$arr!(1, 2), Some(x), Option<&'static [$Ty]>); + compare_evaluation!([x, .., _], &$arr!(1, 2), Some(x), Option<&'static $Ty>); + compare_evaluation!([_, .., x], &$arr!(1, 2), Some(x), Option<&'static $Ty>); + + compare_evaluation!([_, x @ .., _], &$arr!(1), Some(x), Option<&'static [$Ty]>); + compare_evaluation!([x, .., _], &$arr!(1), Some(x), Option<&'static $Ty>); + compare_evaluation!([_, .., x], &$arr!(1), Some(x), Option<&'static $Ty>); + } + + compare_evaluation!([N(x), .., _], &n!(1, 2, 3, 4), Some(x), Option<&'static u8>); + compare_evaluation!([_, .., N(x)], &n!(1, 2, 3, 4), Some(x), Option<&'static u8>); + + compare_evaluation!([N(x), .., _], &n!(1, 2), Some(x), Option<&'static u8>); + compare_evaluation!([_, .., N(x)], &n!(1, 2), Some(x), Option<&'static u8>); +} diff --git a/src/test/ui/array-slice-vec/subslice-patterns-const-eval.rs b/src/test/ui/array-slice-vec/subslice-patterns-const-eval.rs new file mode 100644 index 0000000000000..5444f8a9051bd --- /dev/null +++ b/src/test/ui/array-slice-vec/subslice-patterns-const-eval.rs @@ -0,0 +1,97 @@ +// Test that array subslice patterns are correctly handled in const evaluation. + +// run-pass + +#![feature(slice_patterns)] + +#[derive(PartialEq, Debug, Clone)] +struct N(u8); + +#[derive(PartialEq, Debug, Clone)] +struct Z; + +macro_rules! n { + ($($e:expr),* $(,)?) => { + [$(N($e)),*] + } +} + +// This macro has an unused variable so that it can be repeated base on the +// number of times a repeated variable (`$e` in `z`) occurs. +macro_rules! zed { + ($e:expr) => { Z } +} + +macro_rules! z { + ($($e:expr),* $(,)?) => { + [$(zed!($e)),*] + } +} + +// Compare constant evaluation and runtime evaluation of a given expression. +macro_rules! compare_evaluation { + ($e:expr, $t:ty $(,)?) => {{ + const CONST_EVAL: $t = $e; + const fn const_eval() -> $t { $e } + static CONST_EVAL2: $t = const_eval(); + let runtime_eval = $e; + assert_eq!(CONST_EVAL, runtime_eval); + assert_eq!(CONST_EVAL2, runtime_eval); + }} +} + +// Repeat `$test`, substituting the given macro variables with the given +// identifiers. +// +// For example: +// +// repeat! { +// ($name); X; Y: +// struct $name; +// } +// +// Expands to: +// +// struct X; struct Y; +// +// This is used to repeat the tests using both the `N` and `Z` +// types. +macro_rules! repeat { + (($($dollar:tt $placeholder:ident)*); $($($values:ident),+);*: $($test:tt)*) => { + macro_rules! single { + ($($dollar $placeholder:ident),*) => { $($test)* } + } + $(single!($($values),+);)* + } +} + +fn main() { + repeat! { + ($arr $Ty); n, N; z, Z: + compare_evaluation!({ let [_, x @ .., _] = $arr!(1, 2, 3, 4); x }, [$Ty; 2]); + compare_evaluation!({ let [_, ref x @ .., _] = $arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]); + compare_evaluation!({ let [_, x @ .., _] = &$arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]); + + compare_evaluation!({ let [_, _, x @ .., _, _] = $arr!(1, 2, 3, 4); x }, [$Ty; 0]); + compare_evaluation!( + { let [_, _, ref x @ .., _, _] = $arr!(1, 2, 3, 4); x }, + &'static [$Ty; 0], + ); + compare_evaluation!( + { let [_, _, x @ .., _, _] = &$arr!(1, 2, 3, 4); x }, + &'static [$Ty; 0], + ); + + compare_evaluation!({ let [_, .., x] = $arr!(1, 2, 3, 4); x }, $Ty); + compare_evaluation!({ let [_, .., ref x] = $arr!(1, 2, 3, 4); x }, &'static $Ty); + compare_evaluation!({ let [_, _y @ .., x] = &$arr!(1, 2, 3, 4); x }, &'static $Ty); + } + + compare_evaluation!({ let [_, .., N(x)] = n!(1, 2, 3, 4); x }, u8); + compare_evaluation!({ let [_, .., N(ref x)] = n!(1, 2, 3, 4); x }, &'static u8); + compare_evaluation!({ let [_, .., N(x)] = &n!(1, 2, 3, 4); x }, &'static u8); + + compare_evaluation!({ let [N(x), .., _] = n!(1, 2, 3, 4); x }, u8); + compare_evaluation!({ let [N(ref x), .., _] = n!(1, 2, 3, 4); x }, &'static u8); + compare_evaluation!({ let [N(x), .., _] = &n!(1, 2, 3, 4); x }, &'static u8); +} diff --git a/src/test/ui/borrowck/borrowck-closures-slice-patterns-ok.rs b/src/test/ui/borrowck/borrowck-closures-slice-patterns-ok.rs new file mode 100644 index 0000000000000..a70ccb7aa4b73 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-closures-slice-patterns-ok.rs @@ -0,0 +1,118 @@ +// Check that closure captures for slice patterns are inferred correctly + +#![feature(slice_patterns)] +#![allow(unused_variables)] + +// run-pass + +fn arr_by_ref(x: [String; 3]) { + let r = &x; + let f = || { + let [ref y, ref z @ ..] = x; + }; + f(); + f(); + // Ensure `x` was borrowed + drop(r); + // Ensure that `x` wasn't moved from. + drop(x); +} + +fn arr_by_mut(mut x: [String; 3]) { + let mut f = || { + let [ref mut y, ref mut z @ ..] = x; + }; + f(); + f(); + drop(x); +} + +fn arr_by_move(x: [String; 3]) { + let f = || { + let [y, z @ ..] = x; + }; + f(); +} + +fn arr_ref_by_ref(x: &[String; 3]) { + let r = &x; + let f = || { + let [ref y, ref z @ ..] = *x; + }; + let g = || { + let [y, z @ ..] = x; + }; + f(); + g(); + f(); + g(); + drop(r); + drop(x); +} + +fn arr_ref_by_mut(x: &mut [String; 3]) { + let mut f = || { + let [ref mut y, ref mut z @ ..] = *x; + }; + f(); + f(); + let mut g = || { + let [y, z @ ..] = x; + // Ensure binding mode was chosen correctly: + std::mem::swap(y, &mut z[0]); + }; + g(); + g(); + drop(x); +} + +fn arr_box_by_move(x: Box<[String; 3]>) { + let f = || { + let [y, z @ ..] = *x; + }; + f(); +} + +fn slice_by_ref(x: &[String]) { + let r = &x; + let f = || { + if let [ref y, ref z @ ..] = *x {} + }; + let g = || { + if let [y, z @ ..] = x {} + }; + f(); + g(); + f(); + g(); + drop(r); + drop(x); +} + +fn slice_by_mut(x: &mut [String]) { + let mut f = || { + if let [ref mut y, ref mut z @ ..] = *x {} + }; + f(); + f(); + let mut g = || { + if let [y, z @ ..] = x { + // Ensure binding mode was chosen correctly: + std::mem::swap(y, &mut z[0]); + } + }; + g(); + g(); + drop(x); +} + +fn main() { + arr_by_ref(Default::default()); + arr_by_mut(Default::default()); + arr_by_move(Default::default()); + arr_ref_by_ref(&Default::default()); + arr_ref_by_mut(&mut Default::default()); + arr_box_by_move(Default::default()); + slice_by_ref(&<[_; 3]>::default()); + slice_by_mut(&mut <[_; 3]>::default()); +} diff --git a/src/test/ui/borrowck/borrowck-closures-slice-patterns.rs b/src/test/ui/borrowck/borrowck-closures-slice-patterns.rs new file mode 100644 index 0000000000000..984eb8804b7a2 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-closures-slice-patterns.rs @@ -0,0 +1,84 @@ +// Check that closure captures for slice patterns are inferred correctly + +#![feature(slice_patterns)] + +fn arr_by_ref(mut x: [String; 3]) { + let f = || { + let [ref y, ref z @ ..] = x; + }; + let r = &mut x; + //~^ ERROR cannot borrow + f(); +} + +fn arr_by_mut(mut x: [String; 3]) { + let mut f = || { + let [ref mut y, ref mut z @ ..] = x; + }; + let r = &x; + //~^ ERROR cannot borrow + f(); +} + +fn arr_by_move(x: [String; 3]) { + let f = || { + let [y, z @ ..] = x; + }; + &x; + //~^ ERROR borrow of moved value +} + +fn arr_ref_by_ref(x: &mut [String; 3]) { + let f = || { + let [ref y, ref z @ ..] = *x; + }; + let r = &mut *x; + //~^ ERROR cannot borrow + f(); +} + +fn arr_ref_by_uniq(x: &mut [String; 3]) { + let mut f = || { + let [ref mut y, ref mut z @ ..] = *x; + }; + let r = &x; + //~^ ERROR cannot borrow + f(); +} + +fn arr_box_by_move(x: Box<[String; 3]>) { + let f = || { + let [y, z @ ..] = *x; + }; + &x; + //~^ ERROR borrow of moved value +} + +fn slice_by_ref(x: &mut [String]) { + let f = || { + if let [ref y, ref z @ ..] = *x {} + }; + let r = &mut *x; + //~^ ERROR cannot borrow + f(); +} + +fn slice_by_uniq(x: &mut [String]) { + let mut f = || { + if let [ref mut y, ref mut z @ ..] = *x {} + }; + let r = &x; + //~^ ERROR cannot borrow + f(); +} + +fn main() { + arr_by_ref(Default::default()); + arr_by_mut(Default::default()); + arr_by_move(Default::default()); + arr_ref_by_ref(&mut Default::default()); + arr_ref_by_uniq(&mut Default::default()); + arr_box_by_move(Default::default()); + slice_by_ref(&mut <[_; 3]>::default()); + slice_by_uniq(&mut <[_; 3]>::default()); +} diff --git a/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr new file mode 100644 index 0000000000000..c5b27f5f8b403 --- /dev/null +++ b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr @@ -0,0 +1,114 @@ +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-closures-slice-patterns.rs:9:13 + | +LL | let f = || { + | -- immutable borrow occurs here +LL | let [ref y, ref z @ ..] = x; + | - first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &mut x; + | ^^^^^^ mutable borrow occurs here +LL | +LL | f(); + | - immutable borrow later used here + +error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable + --> $DIR/borrowck-closures-slice-patterns.rs:18:13 + | +LL | let mut f = || { + | -- mutable borrow occurs here +LL | let [ref mut y, ref mut z @ ..] = x; + | - first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &x; + | ^^ immutable borrow occurs here +LL | +LL | f(); + | - mutable borrow later used here + +error[E0382]: borrow of moved value: `x` + --> $DIR/borrowck-closures-slice-patterns.rs:27:5 + | +LL | fn arr_by_move(x: [String; 3]) { + | - move occurs because `x` has type `[std::string::String; 3]`, which does not implement the `Copy` trait +LL | let f = || { + | -- value moved into closure here +LL | let [y, z @ ..] = x; + | - variable moved due to use in closure +LL | }; +LL | &x; + | ^^ value borrowed here after move + +error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-closures-slice-patterns.rs:35:13 + | +LL | let f = || { + | -- immutable borrow occurs here +LL | let [ref y, ref z @ ..] = *x; + | - first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &mut *x; + | ^^^^^^^ mutable borrow occurs here +LL | +LL | f(); + | - immutable borrow later used here + +error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access + --> $DIR/borrowck-closures-slice-patterns.rs:44:13 + | +LL | let mut f = || { + | -- closure construction occurs here +LL | let [ref mut y, ref mut z @ ..] = *x; + | - first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &x; + | ^^ second borrow occurs here +LL | +LL | f(); + | - first borrow later used here + +error[E0382]: borrow of moved value: `x` + --> $DIR/borrowck-closures-slice-patterns.rs:53:5 + | +LL | fn arr_box_by_move(x: Box<[String; 3]>) { + | - move occurs because `x` has type `std::boxed::Box<[std::string::String; 3]>`, which does not implement the `Copy` trait +LL | let f = || { + | -- value moved into closure here +LL | let [y, z @ ..] = *x; + | - variable moved due to use in closure +LL | }; +LL | &x; + | ^^ value borrowed here after move + +error[E0502]: cannot borrow `*x` as mutable because it is also borrowed as immutable + --> $DIR/borrowck-closures-slice-patterns.rs:61:13 + | +LL | let f = || { + | -- immutable borrow occurs here +LL | if let [ref y, ref z @ ..] = *x {} + | - first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &mut *x; + | ^^^^^^^ mutable borrow occurs here +LL | +LL | f(); + | - immutable borrow later used here + +error[E0501]: cannot borrow `x` as immutable because previous closure requires unique access + --> $DIR/borrowck-closures-slice-patterns.rs:70:13 + | +LL | let mut f = || { + | -- closure construction occurs here +LL | if let [ref mut y, ref mut z @ ..] = *x {} + | - first borrow occurs due to use of `x` in closure +LL | }; +LL | let r = &x; + | ^^ second borrow occurs here +LL | +LL | f(); + | - first borrow later used here + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0382, E0501, E0502. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-out-of-array-ref.rs b/src/test/ui/moves/move-out-of-array-ref.rs new file mode 100644 index 0000000000000..4ca60ddfec27c --- /dev/null +++ b/src/test/ui/moves/move-out-of-array-ref.rs @@ -0,0 +1,36 @@ +// Ensure that we cannot move out of a reference to a fixed-size array + +#![feature(slice_patterns)] + +struct D { _x: u8 } + +impl Drop for D { fn drop(&mut self) { } } + +fn move_elem(a: &[D; 4]) -> D { + let [_, e, _, _] = *a; //~ ERROR cannot move + e +} + +fn move_subarr(a: &[D; 4]) -> [D; 2] { + let [_, s @ .. , _] = *a; //~ ERROR cannot move + s +} + +fn move_elem_mut(a: &mut [D; 4]) -> D { + let [_, e, _, _] = *a; //~ ERROR cannot move + e +} + +fn move_subarr_mut(a: &mut [D; 4]) -> [D; 2] { + let [_, s @ .. , _] = *a; //~ ERROR cannot move + s +} + +fn main() { + fn d() -> D { D { _x: 0 } } + + move_elem(&[d(), d(), d(), d()]); + move_subarr(&[d(), d(), d(), d()]); + move_elem_mut(&mut [d(), d(), d(), d()]); + move_subarr_mut(&mut [d(), d(), d(), d()]); +} diff --git a/src/test/ui/moves/move-out-of-array-ref.stderr b/src/test/ui/moves/move-out-of-array-ref.stderr new file mode 100644 index 0000000000000..ae3d2f5f2826a --- /dev/null +++ b/src/test/ui/moves/move-out-of-array-ref.stderr @@ -0,0 +1,47 @@ +error[E0508]: cannot move out of type `[D; 4]`, a non-copy array + --> $DIR/move-out-of-array-ref.rs:10:24 + | +LL | let [_, e, _, _] = *a; + | - ^^ + | | | + | | cannot move out of here + | | help: consider borrowing here: `&*a` + | data moved here + | move occurs because `e` has type `D`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[D; 4]`, a non-copy array + --> $DIR/move-out-of-array-ref.rs:15:27 + | +LL | let [_, s @ .. , _] = *a; + | ------ ^^ + | | | + | | cannot move out of here + | | help: consider borrowing here: `&*a` + | data moved here + | move occurs because `s` has type `[D; 2]`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[D; 4]`, a non-copy array + --> $DIR/move-out-of-array-ref.rs:20:24 + | +LL | let [_, e, _, _] = *a; + | - ^^ + | | | + | | cannot move out of here + | | help: consider borrowing here: `&*a` + | data moved here + | move occurs because `e` has type `D`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[D; 4]`, a non-copy array + --> $DIR/move-out-of-array-ref.rs:25:27 + | +LL | let [_, s @ .. , _] = *a; + | ------ ^^ + | | | + | | cannot move out of here + | | help: consider borrowing here: `&*a` + | data moved here + | move occurs because `s` has type `[D; 2]`, which does not implement the `Copy` trait + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0508`. diff --git a/src/test/ui/moves/move-out-of-slice-2.rs b/src/test/ui/moves/move-out-of-slice-2.rs new file mode 100644 index 0000000000000..e460246193e5b --- /dev/null +++ b/src/test/ui/moves/move-out-of-slice-2.rs @@ -0,0 +1,34 @@ +#![feature(slice_patterns, unsized_locals)] + +struct A; +#[derive(Clone, Copy)] +struct C; + +fn main() { + let a: Box<[A]> = Box::new([A]); + match *a { + //~^ ERROR cannot move out of type `[A]`, a non-copy slice + [a @ ..] => {}, + _ => {} + } + let b: Box<[A]> = Box::new([A, A, A]); + match *b { + //~^ ERROR cannot move out of type `[A]`, a non-copy slice + [_, _, b @ .., _] => {}, + _ => {} + } + + // `[C]` isn't `Copy`, even if `C` is. + let c: Box<[C]> = Box::new([C]); + match *c { + //~^ ERROR cannot move out of type `[C]`, a non-copy slice + [c @ ..] => {}, + _ => {} + } + let d: Box<[C]> = Box::new([C, C, C]); + match *d { + //~^ ERROR cannot move out of type `[C]`, a non-copy slice + [_, _, d @ .., _] => {}, + _ => {} + } +} diff --git a/src/test/ui/moves/move-out-of-slice-2.stderr b/src/test/ui/moves/move-out-of-slice-2.stderr new file mode 100644 index 0000000000000..058f34b24a3b6 --- /dev/null +++ b/src/test/ui/moves/move-out-of-slice-2.stderr @@ -0,0 +1,51 @@ +error[E0508]: cannot move out of type `[A]`, a non-copy slice + --> $DIR/move-out-of-slice-2.rs:9:11 + | +LL | match *a { + | ^^ cannot move out of here +LL | +LL | [a @ ..] => {}, + | ------ + | | + | data moved here + | move occurs because `a` has type `[A]`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[A]`, a non-copy slice + --> $DIR/move-out-of-slice-2.rs:15:11 + | +LL | match *b { + | ^^ cannot move out of here +LL | +LL | [_, _, b @ .., _] => {}, + | ------ + | | + | data moved here + | move occurs because `b` has type `[A]`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[C]`, a non-copy slice + --> $DIR/move-out-of-slice-2.rs:23:11 + | +LL | match *c { + | ^^ cannot move out of here +LL | +LL | [c @ ..] => {}, + | ------ + | | + | data moved here + | move occurs because `c` has type `[C]`, which does not implement the `Copy` trait + +error[E0508]: cannot move out of type `[C]`, a non-copy slice + --> $DIR/move-out-of-slice-2.rs:29:11 + | +LL | match *d { + | ^^ cannot move out of here +LL | +LL | [_, _, d @ .., _] => {}, + | ------ + | | + | data moved here + | move occurs because `d` has type `[C]`, which does not implement the `Copy` trait + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0508`.