Skip to content

Commit 3c80886

Browse files
author
Ariel Ben-Yehuda
committed
prohibit splitting literal patterns
Before PR rust-lang#32202, check_match tended to report bogus errors or ICE when encountering a pattern that split a literal, e.g. ```Rust match foo { "bar" => {}, &_ => {} } ``` That PR fixed these issues, but trans::_match generates bad code when it encounters these matches. MIR trans has that fixed, but it is waiting for 6 weeks in beta. Report an error when encountering these instead. Fixes issue rust-lang#35044.
1 parent f0d4d74 commit 3c80886

File tree

2 files changed

+85
-1
lines changed

2 files changed

+85
-1
lines changed

src/librustc_const_eval/check_match.rs

+39-1
Original file line numberDiff line numberDiff line change
@@ -706,9 +706,12 @@ fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
706706
debug!("is_useful - pat_constructors = {:?} left_ty = {:?}", constructors,
707707
left_ty);
708708
if constructors.is_empty() {
709+
// v[0] is a wildcard pattern - `pat_constructors` should really be returning
710+
// an Option.
709711
let constructors = missing_constructors(cx, matrix, left_ty, max_slice_length);
710712
debug!("is_useful - missing_constructors = {:?}", constructors);
711713
if constructors.is_empty() {
714+
// all constructors are covered - must check them all.
712715
all_constructors(cx, left_ty, max_slice_length).into_iter().map(|c| {
713716
match is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness) {
714717
UsefulWithWitness(pats) => UsefulWithWitness({
@@ -727,6 +730,7 @@ fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
727730
}
728731
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
729732
} else {
733+
// some constructor is only covered by wildcards - pick it.
730734
let matrix = rows.iter().filter_map(|r| {
731735
match raw_pat(r[0].0).node {
732736
PatKind::Binding(..) | PatKind::Wild => Some(r[1..].to_vec()),
@@ -747,12 +751,41 @@ fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
747751
}
748752
}
749753
} else {
754+
// `v` is not a wildcard
750755
constructors.into_iter().map(|c|
751756
is_useful_specialized(cx, matrix, v, c.clone(), left_ty, witness)
752757
).find(|result| result != &NotUseful).unwrap_or(NotUseful)
753758
}
754759
}
755760

761+
fn check_for_ref_splitting<'s, 'a, 'tcx, I>(cx: &MatchCheckCtxt<'a, 'tcx>, data: I)
762+
where I: Iterator<Item=(&'s Pat, Option<Ty<'tcx>>)>
763+
{
764+
let mut ref_pattern = None;
765+
let mut lit_pattern = None;
766+
767+
for (pat, _ty) in data {
768+
match pat.node {
769+
PatKind::Lit(..) => {
770+
lit_pattern = Some(pat);
771+
}
772+
PatKind::Ref(..) => {
773+
ref_pattern = Some(pat);
774+
}
775+
_ => {}
776+
};
777+
if let (Some(lit_pattern), Some(ref_pattern)) = (lit_pattern, ref_pattern) {
778+
cx.tcx.sess.struct_span_err(
779+
ref_pattern.span,
780+
&format!("as a temporary restriction, literal patterns can't be split \
781+
- see issue #35044")
782+
).span_note(lit_pattern.span, &format!("split literal here"))
783+
.emit();
784+
cx.tcx.sess.abort_if_errors();
785+
}
786+
}
787+
}
788+
756789
fn is_useful_specialized<'a, 'tcx>(
757790
cx: &MatchCheckCtxt<'a, 'tcx>,
758791
&Matrix(ref m): &Matrix<'a, 'tcx>,
@@ -762,6 +795,10 @@ fn is_useful_specialized<'a, 'tcx>(
762795
witness: WitnessPreference) -> Usefulness
763796
{
764797
let arity = constructor_arity(cx, &ctor, lty);
798+
check_for_ref_splitting(
799+
cx,
800+
m.iter().map(|r| r[0]).chain(Some(v[0]))
801+
);
765802
let matrix = Matrix(m.iter().filter_map(|r| {
766803
specialize(cx, &r[..], &ctor, 0, arity)
767804
}).collect());
@@ -781,7 +818,8 @@ fn is_useful_specialized<'a, 'tcx>(
781818
/// On the other hand, a wild pattern and an identifier pattern cannot be
782819
/// specialized in any way.
783820
fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
784-
left_ty: Ty, max_slice_length: usize) -> Vec<Constructor> {
821+
left_ty: Ty, max_slice_length: usize)
822+
-> Vec<Constructor> {
785823
let pat = raw_pat(p);
786824
match pat.node {
787825
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) =>

src/test/compile-fail/issue-35044.rs

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#[derive(Debug, PartialEq)]
12+
enum Reg {
13+
EAX,
14+
EBX,
15+
ECX,
16+
EDX,
17+
ESP,
18+
EBP,
19+
ISP,
20+
}
21+
22+
fn string_to_reg(_s:&str) -> Reg {
23+
match _s.as_ref() {
24+
"EAX" => Reg::EAX,
25+
"EBX" => Reg::EBX,
26+
"ECX" => Reg::ECX,
27+
"EDX" => Reg::EDX,
28+
"EBP" => Reg::EBP,
29+
"ESP" => Reg::ESP,
30+
"ISP" => Reg::ISP, //~ NOTE split literal here
31+
&_ => panic!("bla bla bla"), //~ ERROR see issue #35044
32+
}
33+
}
34+
35+
fn main() {
36+
let vec = vec!["EAX", "EBX", "ECX", "EDX", "ESP", "EBP", "ISP"];
37+
let mut iter = vec.iter();
38+
println!("{:?}", string_to_reg(""));
39+
println!("{:?}", string_to_reg(iter.next().unwrap()));
40+
println!("{:?}", string_to_reg(iter.next().unwrap()));
41+
println!("{:?}", string_to_reg(iter.next().unwrap()));
42+
println!("{:?}", string_to_reg(iter.next().unwrap()));
43+
println!("{:?}", string_to_reg(iter.next().unwrap()));
44+
println!("{:?}", string_to_reg(iter.next().unwrap()));
45+
println!("{:?}", string_to_reg(iter.next().unwrap()));
46+
}

0 commit comments

Comments
 (0)