Skip to content

Commit 0a2813c

Browse files
authored
Rollup merge of rust-lang#67467 - matthewjasper:test-slice-patterns, r=oli-obk
Test slice patterns more Adds tests for const evaluation and some more borrow checking tests. Fixes some bugs in const eval for subslice patterns. closes rust-lang#66934 r? @oli-obk cc @Centril
2 parents f43ced3 + 8c3c446 commit 0a2813c

11 files changed

+703
-4
lines changed

Diff for: src/librustc_mir/interpret/operand.rs

+16-2
Original file line numberDiff line numberDiff line change
@@ -444,13 +444,27 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
444444
Field(field, _) => self.operand_field(base, field.index() as u64)?,
445445
Downcast(_, variant) => self.operand_downcast(base, variant)?,
446446
Deref => self.deref_operand(base)?.into(),
447-
Subslice { .. } | ConstantIndex { .. } | Index(_) => if base.layout.is_zst() {
447+
ConstantIndex { .. } | Index(_) if base.layout.is_zst() => {
448448
OpTy {
449449
op: Operand::Immediate(Scalar::zst().into()),
450450
// the actual index doesn't matter, so we just pick a convenient one like 0
451451
layout: base.layout.field(self, 0)?,
452452
}
453-
} else {
453+
}
454+
Subslice { from, to, from_end } if base.layout.is_zst() => {
455+
let elem_ty = if let ty::Array(elem_ty, _) = base.layout.ty.kind {
456+
elem_ty
457+
} else {
458+
bug!("slices shouldn't be zero-sized");
459+
};
460+
assert!(!from_end, "arrays shouldn't be subsliced from the end");
461+
462+
OpTy {
463+
op: Operand::Immediate(Scalar::zst().into()),
464+
layout: self.layout_of(self.tcx.mk_array(elem_ty, (to - from) as u64))?,
465+
}
466+
}
467+
Subslice { .. } | ConstantIndex { .. } | Index(_) => {
454468
// The rest should only occur as mplace, we do not use Immediates for types
455469
// allowing such operations. This matches place_projection forcing an allocation.
456470
let mplace = base.assert_mem_place();

Diff for: src/librustc_mir/interpret/place.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -455,7 +455,10 @@ where
455455
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
456456
let len = base.len(self)?; // also asserts that we have a type where this makes sense
457457
let actual_to = if from_end {
458-
assert!(from <= len - to);
458+
if from + to > len {
459+
// This can only be reached in ConstProp and non-rustc-MIR.
460+
throw_ub!(BoundsCheckFailed { len: len as u64, index: from as u64 + to as u64 });
461+
}
459462
len - to
460463
} else {
461464
to
@@ -523,7 +526,11 @@ where
523526
from_end,
524527
} => {
525528
let n = base.len(self)?;
526-
assert!(n >= min_length as u64);
529+
if n < min_length as u64 {
530+
// This can only be reached in ConstProp and non-rustc-MIR.
531+
throw_ub!(BoundsCheckFailed { len: min_length as u64, index: n as u64 });
532+
}
533+
assert!(offset < min_length);
527534

528535
let index = if from_end {
529536
n - u64::from(offset)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Test that slice subslice patterns are correctly handled in const evaluation.
2+
3+
// run-pass
4+
5+
#![feature(slice_patterns, const_fn, const_if_match)]
6+
#[derive(PartialEq, Debug, Clone)]
7+
struct N(u8);
8+
9+
#[derive(PartialEq, Debug, Clone)]
10+
struct Z;
11+
12+
macro_rules! n {
13+
($($e:expr),* $(,)?) => {
14+
[$(N($e)),*]
15+
}
16+
}
17+
18+
// This macro has an unused variable so that it can be repeated base on the
19+
// number of times a repeated variable (`$e` in `z`) occurs.
20+
macro_rules! zed {
21+
($e:expr) => { Z }
22+
}
23+
24+
macro_rules! z {
25+
($($e:expr),* $(,)?) => {
26+
[$(zed!($e)),*]
27+
}
28+
}
29+
30+
// Compare constant evaluation and runtime evaluation of a given expression.
31+
macro_rules! compare_evaluation_inner {
32+
($e:expr, $t:ty $(,)?) => {{
33+
const CONST_EVAL: $t = $e;
34+
const fn const_eval() -> $t { $e }
35+
static CONST_EVAL2: $t = const_eval();
36+
let runtime_eval = $e;
37+
assert_eq!(CONST_EVAL, runtime_eval);
38+
assert_eq!(CONST_EVAL2, runtime_eval);
39+
}}
40+
}
41+
42+
// Compare the result of matching `$e` against `$p` using both `if let` and
43+
// `match`.
44+
macro_rules! compare_evaluation {
45+
($p:pat, $e:expr, $matches:expr, $t:ty $(,)?) => {{
46+
compare_evaluation_inner!(if let $p = $e as &[_] { $matches } else { None }, $t);
47+
compare_evaluation_inner!(match $e as &[_] { $p => $matches, _ => None }, $t);
48+
}}
49+
}
50+
51+
// Repeat `$test`, substituting the given macro variables with the given
52+
// identifiers.
53+
//
54+
// For example:
55+
//
56+
// repeat! {
57+
// ($name); X; Y:
58+
// struct $name;
59+
// }
60+
//
61+
// Expands to:
62+
//
63+
// struct X; struct Y;
64+
//
65+
// This is used to repeat the tests using both the `N` and `Z`
66+
// types.
67+
macro_rules! repeat {
68+
(($($dollar:tt $placeholder:ident)*); $($($values:ident),+);*: $($test:tt)*) => {
69+
macro_rules! single {
70+
($($dollar $placeholder:ident),*) => { $($test)* }
71+
}
72+
$(single!($($values),+);)*
73+
}
74+
}
75+
76+
fn main() {
77+
repeat! {
78+
($arr $Ty); n, N; z, Z:
79+
compare_evaluation!([_, x @ .., _], &$arr!(1, 2, 3, 4), Some(x), Option<&'static [$Ty]>);
80+
compare_evaluation!([x, .., _], &$arr!(1, 2, 3, 4), Some(x), Option<&'static $Ty>);
81+
compare_evaluation!([_, .., x], &$arr!(1, 2, 3, 4), Some(x), Option<&'static $Ty>);
82+
83+
compare_evaluation!([_, x @ .., _], &$arr!(1, 2), Some(x), Option<&'static [$Ty]>);
84+
compare_evaluation!([x, .., _], &$arr!(1, 2), Some(x), Option<&'static $Ty>);
85+
compare_evaluation!([_, .., x], &$arr!(1, 2), Some(x), Option<&'static $Ty>);
86+
87+
compare_evaluation!([_, x @ .., _], &$arr!(1), Some(x), Option<&'static [$Ty]>);
88+
compare_evaluation!([x, .., _], &$arr!(1), Some(x), Option<&'static $Ty>);
89+
compare_evaluation!([_, .., x], &$arr!(1), Some(x), Option<&'static $Ty>);
90+
}
91+
92+
compare_evaluation!([N(x), .., _], &n!(1, 2, 3, 4), Some(x), Option<&'static u8>);
93+
compare_evaluation!([_, .., N(x)], &n!(1, 2, 3, 4), Some(x), Option<&'static u8>);
94+
95+
compare_evaluation!([N(x), .., _], &n!(1, 2), Some(x), Option<&'static u8>);
96+
compare_evaluation!([_, .., N(x)], &n!(1, 2), Some(x), Option<&'static u8>);
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Test that array subslice patterns are correctly handled in const evaluation.
2+
3+
// run-pass
4+
5+
#![feature(slice_patterns)]
6+
7+
#[derive(PartialEq, Debug, Clone)]
8+
struct N(u8);
9+
10+
#[derive(PartialEq, Debug, Clone)]
11+
struct Z;
12+
13+
macro_rules! n {
14+
($($e:expr),* $(,)?) => {
15+
[$(N($e)),*]
16+
}
17+
}
18+
19+
// This macro has an unused variable so that it can be repeated base on the
20+
// number of times a repeated variable (`$e` in `z`) occurs.
21+
macro_rules! zed {
22+
($e:expr) => { Z }
23+
}
24+
25+
macro_rules! z {
26+
($($e:expr),* $(,)?) => {
27+
[$(zed!($e)),*]
28+
}
29+
}
30+
31+
// Compare constant evaluation and runtime evaluation of a given expression.
32+
macro_rules! compare_evaluation {
33+
($e:expr, $t:ty $(,)?) => {{
34+
const CONST_EVAL: $t = $e;
35+
const fn const_eval() -> $t { $e }
36+
static CONST_EVAL2: $t = const_eval();
37+
let runtime_eval = $e;
38+
assert_eq!(CONST_EVAL, runtime_eval);
39+
assert_eq!(CONST_EVAL2, runtime_eval);
40+
}}
41+
}
42+
43+
// Repeat `$test`, substituting the given macro variables with the given
44+
// identifiers.
45+
//
46+
// For example:
47+
//
48+
// repeat! {
49+
// ($name); X; Y:
50+
// struct $name;
51+
// }
52+
//
53+
// Expands to:
54+
//
55+
// struct X; struct Y;
56+
//
57+
// This is used to repeat the tests using both the `N` and `Z`
58+
// types.
59+
macro_rules! repeat {
60+
(($($dollar:tt $placeholder:ident)*); $($($values:ident),+);*: $($test:tt)*) => {
61+
macro_rules! single {
62+
($($dollar $placeholder:ident),*) => { $($test)* }
63+
}
64+
$(single!($($values),+);)*
65+
}
66+
}
67+
68+
fn main() {
69+
repeat! {
70+
($arr $Ty); n, N; z, Z:
71+
compare_evaluation!({ let [_, x @ .., _] = $arr!(1, 2, 3, 4); x }, [$Ty; 2]);
72+
compare_evaluation!({ let [_, ref x @ .., _] = $arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]);
73+
compare_evaluation!({ let [_, x @ .., _] = &$arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]);
74+
75+
compare_evaluation!({ let [_, _, x @ .., _, _] = $arr!(1, 2, 3, 4); x }, [$Ty; 0]);
76+
compare_evaluation!(
77+
{ let [_, _, ref x @ .., _, _] = $arr!(1, 2, 3, 4); x },
78+
&'static [$Ty; 0],
79+
);
80+
compare_evaluation!(
81+
{ let [_, _, x @ .., _, _] = &$arr!(1, 2, 3, 4); x },
82+
&'static [$Ty; 0],
83+
);
84+
85+
compare_evaluation!({ let [_, .., x] = $arr!(1, 2, 3, 4); x }, $Ty);
86+
compare_evaluation!({ let [_, .., ref x] = $arr!(1, 2, 3, 4); x }, &'static $Ty);
87+
compare_evaluation!({ let [_, _y @ .., x] = &$arr!(1, 2, 3, 4); x }, &'static $Ty);
88+
}
89+
90+
compare_evaluation!({ let [_, .., N(x)] = n!(1, 2, 3, 4); x }, u8);
91+
compare_evaluation!({ let [_, .., N(ref x)] = n!(1, 2, 3, 4); x }, &'static u8);
92+
compare_evaluation!({ let [_, .., N(x)] = &n!(1, 2, 3, 4); x }, &'static u8);
93+
94+
compare_evaluation!({ let [N(x), .., _] = n!(1, 2, 3, 4); x }, u8);
95+
compare_evaluation!({ let [N(ref x), .., _] = n!(1, 2, 3, 4); x }, &'static u8);
96+
compare_evaluation!({ let [N(x), .., _] = &n!(1, 2, 3, 4); x }, &'static u8);
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Check that closure captures for slice patterns are inferred correctly
2+
3+
#![feature(slice_patterns)]
4+
#![allow(unused_variables)]
5+
6+
// run-pass
7+
8+
fn arr_by_ref(x: [String; 3]) {
9+
let r = &x;
10+
let f = || {
11+
let [ref y, ref z @ ..] = x;
12+
};
13+
f();
14+
f();
15+
// Ensure `x` was borrowed
16+
drop(r);
17+
// Ensure that `x` wasn't moved from.
18+
drop(x);
19+
}
20+
21+
fn arr_by_mut(mut x: [String; 3]) {
22+
let mut f = || {
23+
let [ref mut y, ref mut z @ ..] = x;
24+
};
25+
f();
26+
f();
27+
drop(x);
28+
}
29+
30+
fn arr_by_move(x: [String; 3]) {
31+
let f = || {
32+
let [y, z @ ..] = x;
33+
};
34+
f();
35+
}
36+
37+
fn arr_ref_by_ref(x: &[String; 3]) {
38+
let r = &x;
39+
let f = || {
40+
let [ref y, ref z @ ..] = *x;
41+
};
42+
let g = || {
43+
let [y, z @ ..] = x;
44+
};
45+
f();
46+
g();
47+
f();
48+
g();
49+
drop(r);
50+
drop(x);
51+
}
52+
53+
fn arr_ref_by_mut(x: &mut [String; 3]) {
54+
let mut f = || {
55+
let [ref mut y, ref mut z @ ..] = *x;
56+
};
57+
f();
58+
f();
59+
let mut g = || {
60+
let [y, z @ ..] = x;
61+
// Ensure binding mode was chosen correctly:
62+
std::mem::swap(y, &mut z[0]);
63+
};
64+
g();
65+
g();
66+
drop(x);
67+
}
68+
69+
fn arr_box_by_move(x: Box<[String; 3]>) {
70+
let f = || {
71+
let [y, z @ ..] = *x;
72+
};
73+
f();
74+
}
75+
76+
fn slice_by_ref(x: &[String]) {
77+
let r = &x;
78+
let f = || {
79+
if let [ref y, ref z @ ..] = *x {}
80+
};
81+
let g = || {
82+
if let [y, z @ ..] = x {}
83+
};
84+
f();
85+
g();
86+
f();
87+
g();
88+
drop(r);
89+
drop(x);
90+
}
91+
92+
fn slice_by_mut(x: &mut [String]) {
93+
let mut f = || {
94+
if let [ref mut y, ref mut z @ ..] = *x {}
95+
};
96+
f();
97+
f();
98+
let mut g = || {
99+
if let [y, z @ ..] = x {
100+
// Ensure binding mode was chosen correctly:
101+
std::mem::swap(y, &mut z[0]);
102+
}
103+
};
104+
g();
105+
g();
106+
drop(x);
107+
}
108+
109+
fn main() {
110+
arr_by_ref(Default::default());
111+
arr_by_mut(Default::default());
112+
arr_by_move(Default::default());
113+
arr_ref_by_ref(&Default::default());
114+
arr_ref_by_mut(&mut Default::default());
115+
arr_box_by_move(Default::default());
116+
slice_by_ref(&<[_; 3]>::default());
117+
slice_by_mut(&mut <[_; 3]>::default());
118+
}

0 commit comments

Comments
 (0)