Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 14a0b10

Browse files
committedOct 1, 2020
Destructure byte slices and remove all the workarounds
1 parent 002a1c2 commit 14a0b10

File tree

3 files changed

+9
-243
lines changed

3 files changed

+9
-243
lines changed
 

‎compiler/rustc_mir_build/src/thir/pattern/_match.rs

+8-241
Original file line numberDiff line numberDiff line change
@@ -284,10 +284,9 @@ use super::{FieldPat, Pat, PatKind, PatRange};
284284

285285
use rustc_arena::TypedArena;
286286
use rustc_attr::{SignedInt, UnsignedInt};
287-
use rustc_errors::ErrorReported;
288287
use rustc_hir::def_id::DefId;
289288
use rustc_hir::{HirId, RangeEnd};
290-
use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
289+
use rustc_middle::mir::interpret::{truncate, ConstValue};
291290
use rustc_middle::mir::Field;
292291
use rustc_middle::ty::layout::IntegerExt;
293292
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
@@ -296,84 +295,21 @@ use rustc_span::{Span, DUMMY_SP};
296295
use rustc_target::abi::{Integer, Size, VariantIdx};
297296

298297
use smallvec::{smallvec, SmallVec};
299-
use std::borrow::Cow;
300298
use std::cmp::{self, max, min, Ordering};
301-
use std::convert::TryInto;
302299
use std::fmt;
303300
use std::iter::{FromIterator, IntoIterator};
304301
use std::ops::RangeInclusive;
305302

306-
crate fn expand_pattern<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>, pat: Pat<'tcx>) -> Pat<'tcx> {
307-
LiteralExpander { tcx: cx.tcx }.fold_pattern(&pat)
303+
crate fn expand_pattern<'tcx>(pat: Pat<'tcx>) -> Pat<'tcx> {
304+
LiteralExpander.fold_pattern(&pat)
308305
}
309306

310-
struct LiteralExpander<'tcx> {
311-
tcx: TyCtxt<'tcx>,
312-
}
307+
struct LiteralExpander;
313308

314-
impl<'tcx> LiteralExpander<'tcx> {
315-
/// Derefs `val` and potentially unsizes the value if `crty` is an array and `rty` a slice.
316-
///
317-
/// `crty` and `rty` can differ because you can use array constants in the presence of slice
318-
/// patterns. So the pattern may end up being a slice, but the constant is an array. We convert
319-
/// the array to a slice in that case.
320-
fn fold_const_value_deref(
321-
&mut self,
322-
val: ConstValue<'tcx>,
323-
// the pattern's pointee type
324-
rty: Ty<'tcx>,
325-
// the constant's pointee type
326-
crty: Ty<'tcx>,
327-
) -> ConstValue<'tcx> {
328-
debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty);
329-
match (val, &crty.kind(), &rty.kind()) {
330-
// unsize array to slice if pattern is array but match value or other patterns are slice
331-
(ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
332-
assert_eq!(t, u);
333-
assert_eq!(p.offset, Size::ZERO);
334-
ConstValue::Slice {
335-
data: self.tcx.global_alloc(p.alloc_id).unwrap_memory(),
336-
start: 0,
337-
end: n.eval_usize(self.tcx, ty::ParamEnv::empty()).try_into().unwrap(),
338-
}
339-
}
340-
_ => val,
341-
}
342-
}
343-
}
344-
345-
impl<'tcx> PatternFolder<'tcx> for LiteralExpander<'tcx> {
309+
impl<'tcx> PatternFolder<'tcx> for LiteralExpander {
346310
fn fold_pattern(&mut self, pat: &Pat<'tcx>) -> Pat<'tcx> {
347311
debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind);
348312
match (pat.ty.kind(), &*pat.kind) {
349-
(&ty::Ref(_, rty, _), &PatKind::Constant { value: Const { val, ty: const_ty } })
350-
if const_ty.is_ref() =>
351-
{
352-
let crty =
353-
if let ty::Ref(_, crty, _) = const_ty.kind() { crty } else { unreachable!() };
354-
if let ty::ConstKind::Value(val) = val {
355-
Pat {
356-
ty: pat.ty,
357-
span: pat.span,
358-
kind: box PatKind::Deref {
359-
subpattern: Pat {
360-
ty: rty,
361-
span: pat.span,
362-
kind: box PatKind::Constant {
363-
value: Const::from_value(
364-
self.tcx,
365-
self.fold_const_value_deref(*val, rty, crty),
366-
rty,
367-
),
368-
},
369-
},
370-
},
371-
}
372-
} else {
373-
bug!("cannot deref {:#?}, {} -> {}", val, crty, rty)
374-
}
375-
}
376-
377313
(_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self),
378314
(_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self),
379315
_ => pat.super_fold_with(self),
@@ -941,8 +877,6 @@ impl<'tcx> Constructor<'tcx> {
941877
.iter()
942878
.filter_map(|c: &Constructor<'_>| match c {
943879
Slice(slice) => Some(*slice),
944-
// FIXME(oli-obk): implement `deref` for `ConstValue`
945-
ConstantValue(..) => None,
946880
_ => bug!("bad slice pattern constructor {:?}", c),
947881
})
948882
.map(Slice::value_kind);
@@ -1162,12 +1096,6 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
11621096
Fields::Slice(std::slice::from_ref(pat))
11631097
}
11641098

1165-
/// Construct a new `Fields` from the given patterns. You must be sure those patterns can't
1166-
/// contain fields that need to be filtered out. When in doubt, prefer `replace_fields`.
1167-
fn from_slice_unfiltered(pats: &'p [Pat<'tcx>]) -> Self {
1168-
Fields::Slice(pats)
1169-
}
1170-
11711099
/// Convenience; internal use.
11721100
fn wildcards_from_tys(
11731101
cx: &MatchCheckCtxt<'p, 'tcx>,
@@ -2183,19 +2111,7 @@ fn pat_constructor<'tcx>(
21832111
if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) {
21842112
Some(IntRange(int_range))
21852113
} else {
2186-
match (value.val, &value.ty.kind()) {
2187-
(_, ty::Array(_, n)) => {
2188-
let len = n.eval_usize(tcx, param_env);
2189-
Some(Slice(Slice { array_len: Some(len), kind: FixedLen(len) }))
2190-
}
2191-
(ty::ConstKind::Value(ConstValue::Slice { start, end, .. }), ty::Slice(_)) => {
2192-
let len = (end - start) as u64;
2193-
Some(Slice(Slice { array_len: None, kind: FixedLen(len) }))
2194-
}
2195-
// FIXME(oli-obk): implement `deref` for `ConstValue`
2196-
// (ty::ConstKind::Value(ConstValue::ByRef { .. }), ty::Slice(_)) => { ... }
2197-
_ => Some(ConstantValue(value)),
2198-
}
2114+
Some(ConstantValue(value))
21992115
}
22002116
}
22012117
PatKind::Range(PatRange { lo, hi, end }) => {
@@ -2230,75 +2146,6 @@ fn pat_constructor<'tcx>(
22302146
}
22312147
}
22322148

2233-
// checks whether a constant is equal to a user-written slice pattern. Only supports byte slices,
2234-
// meaning all other types will compare unequal and thus equal patterns often do not cause the
2235-
// second pattern to lint about unreachable match arms.
2236-
fn slice_pat_covered_by_const<'tcx>(
2237-
tcx: TyCtxt<'tcx>,
2238-
_span: Span,
2239-
const_val: &'tcx ty::Const<'tcx>,
2240-
prefix: &[Pat<'tcx>],
2241-
slice: &Option<Pat<'tcx>>,
2242-
suffix: &[Pat<'tcx>],
2243-
param_env: ty::ParamEnv<'tcx>,
2244-
) -> Result<bool, ErrorReported> {
2245-
let const_val_val = if let ty::ConstKind::Value(val) = const_val.val {
2246-
val
2247-
} else {
2248-
bug!(
2249-
"slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
2250-
const_val,
2251-
prefix,
2252-
slice,
2253-
suffix,
2254-
)
2255-
};
2256-
2257-
let data: &[u8] = match (const_val_val, &const_val.ty.kind()) {
2258-
(ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => {
2259-
assert_eq!(*t, tcx.types.u8);
2260-
let n = n.eval_usize(tcx, param_env);
2261-
let ptr = Pointer::new(AllocId(0), offset);
2262-
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
2263-
}
2264-
(ConstValue::Slice { data, start, end }, ty::Slice(t)) => {
2265-
assert_eq!(*t, tcx.types.u8);
2266-
let ptr = Pointer::new(AllocId(0), Size::from_bytes(start));
2267-
data.get_bytes(&tcx, ptr, Size::from_bytes(end - start)).unwrap()
2268-
}
2269-
// FIXME(oli-obk): create a way to extract fat pointers from ByRef
2270-
(_, ty::Slice(_)) => return Ok(false),
2271-
_ => bug!(
2272-
"slice_pat_covered_by_const: {:#?}, {:#?}, {:#?}, {:#?}",
2273-
const_val,
2274-
prefix,
2275-
slice,
2276-
suffix,
2277-
),
2278-
};
2279-
2280-
let pat_len = prefix.len() + suffix.len();
2281-
if data.len() < pat_len || (slice.is_none() && data.len() > pat_len) {
2282-
return Ok(false);
2283-
}
2284-
2285-
for (ch, pat) in data[..prefix.len()]
2286-
.iter()
2287-
.zip(prefix)
2288-
.chain(data[data.len() - suffix.len()..].iter().zip(suffix))
2289-
{
2290-
if let box PatKind::Constant { value } = pat.kind {
2291-
let b = value.eval_bits(tcx, param_env, pat.ty);
2292-
assert_eq!(b as u8 as u128, b);
2293-
if b as u8 != *ch {
2294-
return Ok(false);
2295-
}
2296-
}
2297-
}
2298-
2299-
Ok(true)
2300-
}
2301-
23022149
/// For exhaustive integer matching, some constructors are grouped within other constructors
23032150
/// (namely integer typed values are grouped within ranges). However, when specialising these
23042151
/// constructors, we want to be specialising for the underlying constructors (the integers), not
@@ -2670,73 +2517,7 @@ fn specialize_one_pattern<'p, 'tcx>(
26702517
PatKind::Deref { ref subpattern } => Some(Fields::from_single_pattern(subpattern)),
26712518

26722519
PatKind::Constant { value } if constructor.is_slice() => {
2673-
// We extract an `Option` for the pointer because slices of zero
2674-
// elements don't necessarily point to memory, they are usually
2675-
// just integers. The only time they should be pointing to memory
2676-
// is when they are subslices of nonzero slices.
2677-
let (alloc, offset, n, ty) = match value.ty.kind() {
2678-
ty::Array(t, n) => {
2679-
let n = n.eval_usize(cx.tcx, cx.param_env);
2680-
// Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce,
2681-
// the result would be exactly what we early return here.
2682-
if n == 0 {
2683-
if ctor_wild_subpatterns.len() as u64 != n {
2684-
return None;
2685-
}
2686-
return Some(Fields::empty());
2687-
}
2688-
match value.val {
2689-
ty::ConstKind::Value(ConstValue::ByRef { offset, alloc, .. }) => {
2690-
(Cow::Borrowed(alloc), offset, n, t)
2691-
}
2692-
_ => span_bug!(pat.span, "array pattern is {:?}", value,),
2693-
}
2694-
}
2695-
ty::Slice(t) => {
2696-
match value.val {
2697-
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
2698-
let offset = Size::from_bytes(start);
2699-
let n = (end - start) as u64;
2700-
(Cow::Borrowed(data), offset, n, t)
2701-
}
2702-
ty::ConstKind::Value(ConstValue::ByRef { .. }) => {
2703-
// FIXME(oli-obk): implement `deref` for `ConstValue`
2704-
return None;
2705-
}
2706-
_ => span_bug!(
2707-
pat.span,
2708-
"slice pattern constant must be scalar pair but is {:?}",
2709-
value,
2710-
),
2711-
}
2712-
}
2713-
_ => span_bug!(
2714-
pat.span,
2715-
"unexpected const-val {:?} with ctor {:?}",
2716-
value,
2717-
constructor,
2718-
),
2719-
};
2720-
if ctor_wild_subpatterns.len() as u64 != n {
2721-
return None;
2722-
}
2723-
2724-
// Convert a constant slice/array pattern to a list of patterns.
2725-
let layout = cx.tcx.layout_of(cx.param_env.and(ty)).ok()?;
2726-
let ptr = Pointer::new(AllocId(0), offset);
2727-
let pats = cx.pattern_arena.alloc_from_iter((0..n).filter_map(|i| {
2728-
let ptr = ptr.offset(layout.size * i, &cx.tcx).ok()?;
2729-
let scalar = alloc.read_scalar(&cx.tcx, ptr, layout.size).ok()?;
2730-
let scalar = scalar.check_init().ok()?;
2731-
let value = ty::Const::from_scalar(cx.tcx, scalar, ty);
2732-
let pattern = Pat { ty, span: pat.span, kind: box PatKind::Constant { value } };
2733-
Some(pattern)
2734-
}));
2735-
// Ensure none of the dereferences failed.
2736-
if pats.len() as u64 != n {
2737-
return None;
2738-
}
2739-
Some(Fields::from_slice_unfiltered(pats))
2520+
span_bug!(pat.span, "unexpected const-val {:?} with ctor {:?}", value, constructor)
27402521
}
27412522

27422523
PatKind::Constant { .. } | PatKind::Range { .. } => {
@@ -2778,21 +2559,7 @@ fn specialize_one_pattern<'p, 'tcx>(
27782559
let suffix = suffix.iter().enumerate().map(|(i, p)| (arity - suffix.len() + i, p));
27792560
Some(ctor_wild_subpatterns.replace_fields_indexed(prefix.chain(suffix)))
27802561
}
2781-
ConstantValue(cv) => {
2782-
match slice_pat_covered_by_const(
2783-
cx.tcx,
2784-
pat.span,
2785-
cv,
2786-
prefix,
2787-
slice,
2788-
suffix,
2789-
cx.param_env,
2790-
) {
2791-
Ok(true) => Some(Fields::empty()),
2792-
Ok(false) => None,
2793-
Err(ErrorReported) => None,
2794-
}
2795-
}
2562+
ConstantValue(_) => None,
27962563
_ => span_bug!(pat.span, "unexpected ctor {:?} for slice pat", constructor),
27972564
},
27982565

‎compiler/rustc_mir_build/src/thir/pattern/check_match.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
140140
patcx.include_lint_checks();
141141
let pattern = patcx.lower_pattern(pat);
142142
let pattern_ty = pattern.ty;
143-
let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(cx, pattern));
143+
let pattern: &_ = cx.pattern_arena.alloc(expand_pattern(pattern));
144144
if !patcx.errors.is_empty() {
145145
*have_errors = true;
146146
patcx.report_inlining_errors(pat.span);

‎compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs

-1
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,6 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> {
387387
// `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this
388388
// optimization for now.
389389
ty::Str => PatKind::Constant { value: cv },
390-
ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv },
391390
// `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when
392391
// matching against references, you can only use byte string literals.
393392
// The typechecker has a special case for byte string literals, by treating them

0 commit comments

Comments
 (0)
Please sign in to comment.