Skip to content

Commit 6b3d66b

Browse files
committed
Auto merge of #25060 - luqmana:matching-dst-struct, r=huonw
Fixes #23261. cc @blaenk
2 parents 1a60dc4 + 715605f commit 6b3d66b

File tree

2 files changed

+103
-2
lines changed

2 files changed

+103
-2
lines changed

src/librustc_trans/trans/_match.rs

+33-2
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ use trans::consts;
210210
use trans::datum::*;
211211
use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
212212
use trans::expr::{self, Dest};
213+
use trans::monomorphize;
213214
use trans::tvec;
214215
use trans::type_of;
215216
use middle::ty::{self, Ty};
@@ -1076,9 +1077,39 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
10761077
let adt_vals = if any_irrefutable_adt_pat(bcx.tcx(), m, col) {
10771078
let repr = adt::represent_type(bcx.ccx(), left_ty);
10781079
let arg_count = adt::num_args(&*repr, 0);
1079-
let field_vals: Vec<ValueRef> = (0..arg_count).map(|ix|
1080-
adt::trans_field_ptr(bcx, &*repr, val, 0, ix)
1080+
let (arg_count, struct_val) = if type_is_sized(bcx.tcx(), left_ty) {
1081+
(arg_count, val)
1082+
} else {
1083+
// For an unsized ADT (i.e. DST struct), we need to treat
1084+
// the last field specially: instead of simply passing a
1085+
// ValueRef pointing to that field, as with all the others,
1086+
// we skip it and instead construct a 'fat ptr' below.
1087+
(arg_count - 1, Load(bcx, expr::get_dataptr(bcx, val)))
1088+
};
1089+
let mut field_vals: Vec<ValueRef> = (0..arg_count).map(|ix|
1090+
adt::trans_field_ptr(bcx, &*repr, struct_val, 0, ix)
10811091
).collect();
1092+
1093+
match left_ty.sty {
1094+
ty::ty_struct(def_id, substs) if !type_is_sized(bcx.tcx(), left_ty) => {
1095+
// The last field is technically unsized but
1096+
// since we can only ever match that field behind
1097+
// a reference we construct a fat ptr here.
1098+
let fields = ty::lookup_struct_fields(bcx.tcx(), def_id);
1099+
let unsized_ty = fields.iter().last().map(|field| {
1100+
let fty = ty::lookup_field_type(bcx.tcx(), def_id, field.id, substs);
1101+
monomorphize::normalize_associated_type(bcx.tcx(), &fty)
1102+
}).unwrap();
1103+
let llty = type_of::type_of(bcx.ccx(), unsized_ty);
1104+
let scratch = alloca_no_lifetime(bcx, llty, "__struct_field_fat_ptr");
1105+
let data = adt::trans_field_ptr(bcx, &*repr, struct_val, 0, arg_count);
1106+
let len = Load(bcx, expr::get_len(bcx, val));
1107+
Store(bcx, data, expr::get_dataptr(bcx, scratch));
1108+
Store(bcx, len, expr::get_len(bcx, scratch));
1109+
field_vals.push(scratch);
1110+
}
1111+
_ => {}
1112+
}
10821113
Some(field_vals)
10831114
} else if any_uniq_pat(m, col) || any_region_pat(m, col) {
10841115
Some(vec!(Load(bcx, val)))

src/test/run-pass/issue-23261.rs

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2015 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+
// Matching on a DST struct should not trigger an LLVM assertion.
12+
13+
struct Foo<T: ?Sized> {
14+
a: i32,
15+
inner: T
16+
}
17+
18+
trait Get {
19+
fn get(&self) -> i32;
20+
}
21+
22+
impl Get for i32 {
23+
fn get(&self) -> i32 {
24+
*self
25+
}
26+
}
27+
28+
fn check_val(val: &Foo<[u8]>) {
29+
match *val {
30+
Foo { a, .. } => {
31+
assert_eq!(a, 32);
32+
}
33+
}
34+
}
35+
36+
fn check_dst_val(val: &Foo<[u8]>) {
37+
match *val {
38+
Foo { ref inner, .. } => {
39+
assert_eq!(inner, [1, 2, 3]);
40+
}
41+
}
42+
}
43+
44+
fn check_both(val: &Foo<[u8]>) {
45+
match *val {
46+
Foo { a, ref inner } => {
47+
assert_eq!(a, 32);
48+
assert_eq!(inner, [1, 2, 3]);
49+
}
50+
}
51+
}
52+
53+
fn check_trait_obj(val: &Foo<Get>) {
54+
match *val {
55+
Foo { a, ref inner } => {
56+
assert_eq!(a, 32);
57+
assert_eq!(inner.get(), 32);
58+
}
59+
}
60+
}
61+
62+
fn main() {
63+
let foo: &Foo<[u8]> = &Foo { a: 32, inner: [1, 2, 3] };
64+
check_val(foo);
65+
check_dst_val(foo);
66+
check_both(foo);
67+
68+
let foo: &Foo<Get> = &Foo { a: 32, inner: 32 };
69+
check_trait_obj(foo);
70+
}

0 commit comments

Comments
 (0)