Skip to content

Commit 229fbe7

Browse files
committed
Fix byte string literal patterns in match
1 parent 202b301 commit 229fbe7

File tree

3 files changed

+49
-17
lines changed

3 files changed

+49
-17
lines changed

src/librustc_trans/trans/_match.rs

+25-8
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ use middle::mem_categorization as mc;
200200
use middle::pat_util::*;
201201
use trans::adt;
202202
use trans::base::*;
203-
use trans::build::{AddCase, And, BitCast, Br, CondBr, GEPi, InBoundsGEP, Load};
203+
use trans::build::{AddCase, And, Br, CondBr, GEPi, InBoundsGEP, Load, PointerCast};
204204
use trans::build::{Not, Store, Sub, add_comment};
205205
use trans::build;
206206
use trans::callee;
@@ -853,14 +853,31 @@ fn compare_values<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
853853
ty::ty_str => compare_str(cx, lhs, rhs, rhs_t, debug_loc),
854854
ty::ty_vec(ty, _) => match ty.sty {
855855
ty::ty_uint(ast::TyU8) => {
856-
// NOTE: cast &[u8] to &str and abuse the str_eq lang item,
856+
// NOTE: cast &[u8] and &[u8; N] to &str and abuse the str_eq lang item,
857857
// which calls memcmp().
858-
let t = ty::mk_str_slice(cx.tcx(),
859-
cx.tcx().mk_region(ty::ReStatic),
860-
ast::MutImmutable);
861-
let lhs = BitCast(cx, lhs, type_of::type_of(cx.ccx(), t).ptr_to());
862-
let rhs = BitCast(cx, rhs, type_of::type_of(cx.ccx(), t).ptr_to());
863-
compare_str(cx, lhs, rhs, rhs_t, debug_loc)
858+
let pat_len = val_ty(rhs).element_type().array_length();
859+
let ty_str_slice = ty::mk_str_slice(cx.tcx(),
860+
cx.tcx().mk_region(ty::ReStatic),
861+
ast::MutImmutable);
862+
863+
let rhs_str = alloc_ty(cx, ty_str_slice, "rhs_str");
864+
Store(cx, GEPi(cx, rhs, &[0, 0]), expr::get_dataptr(cx, rhs_str));
865+
Store(cx, C_uint(cx.ccx(), pat_len), expr::get_len(cx, rhs_str));
866+
867+
let lhs_str;
868+
if val_ty(lhs) == val_ty(rhs) {
869+
// Both the discriminant and the pattern are thin pointers
870+
lhs_str = alloc_ty(cx, ty_str_slice, "lhs_str");
871+
Store(cx, GEPi(cx, lhs, &[0, 0]), expr::get_dataptr(cx, lhs_str));
872+
Store(cx, C_uint(cx.ccx(), pat_len), expr::get_len(cx, lhs_str));
873+
}
874+
else {
875+
// The discriminant is a fat pointer
876+
let llty_str_slice = type_of::type_of(cx.ccx(), ty_str_slice).ptr_to();
877+
lhs_str = PointerCast(cx, lhs, llty_str_slice);
878+
}
879+
880+
compare_str(cx, lhs_str, rhs_str, rhs_t, debug_loc)
864881
},
865882
_ => cx.sess().bug("only byte strings supported in compare_values"),
866883
},

src/librustc_typeck/check/_match.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,23 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
4848
ast::PatLit(ref lt) => {
4949
check_expr(fcx, &**lt);
5050
let expr_ty = fcx.expr_ty(&**lt);
51-
fcx.write_ty(pat.id, expr_ty);
51+
52+
// Byte string patterns behave the same way as array patterns
53+
// They can denote both statically and dynamically sized byte arrays
54+
let mut pat_ty = expr_ty;
55+
if let ast::ExprLit(ref lt) = lt.node {
56+
if let ast::LitBinary(_) = lt.node {
57+
let expected_ty = structurally_resolved_type(fcx, pat.span, expected);
58+
if let ty::ty_rptr(_, mt) = expected_ty.sty {
59+
if let ty::ty_vec(_, None) = mt.ty.sty {
60+
pat_ty = ty::mk_slice(tcx, tcx.mk_region(ty::ReStatic),
61+
ty::mt{ ty: tcx.types.u8, mutbl: ast::MutImmutable })
62+
}
63+
}
64+
}
65+
}
66+
67+
fcx.write_ty(pat.id, pat_ty);
5268

5369
// somewhat surprising: in this case, the subtyping
5470
// relation goes the opposite way as the other
@@ -62,7 +78,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
6278
// &'static str <: expected
6379
//
6480
// that's equivalent to there existing a LUB.
65-
demand::suptype(fcx, pat.span, expected, expr_ty);
81+
demand::suptype(fcx, pat.span, expected, pat_ty);
6682
}
6783
ast::PatRange(ref begin, ref end) => {
6884
check_expr(fcx, &**begin);

src/test/run-pass/byte-literals.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,12 @@ pub fn main() {
5858
_ => panic!(),
5959
}
6060

61-
// FIXME: There are no DST coercions &[T; N] -> &[T] in patterns
62-
// let buf = vec!(97u8, 98, 99, 100);
63-
// assert_eq!(match &buf[0..3] {
64-
// b"def" => 1_usize,
65-
// b"abc" => 2_usize,
66-
// _ => 3_usize
67-
// }, 2);
61+
let buf = vec!(97u8, 98, 99, 100);
62+
assert_eq!(match &buf[0..3] {
63+
b"def" => 1,
64+
b"abc" => 2,
65+
_ => 3
66+
}, 2);
6867

6968
let expected: &[_] = &[97u8, 92u8, 110u8];
7069
assert_eq!(BAZ, expected);

0 commit comments

Comments
 (0)