-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Test slice patterns more #67467
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Test slice patterns more #67467
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even though the function is public, it's only called for so... probably not, but there may be creative code generators out there |
||
// 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) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 { | ||
Centril marked this conversation as resolved.
Show resolved
Hide resolved
|
||
($($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 { | ||
Centril marked this conversation as resolved.
Show resolved
Hide resolved
|
||
(($($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>); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()); | ||
} |
Uh oh!
There was an error while loading. Please reload this page.