Skip to content

Commit 6a46b86

Browse files
committed
librustc_trans: Handle DST structs in trans::_match.
1 parent 5574029 commit 6a46b86

File tree

2 files changed

+99
-2
lines changed

2 files changed

+99
-2
lines changed

src/librustc_trans/trans/_match.rs

+29-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,35 @@ 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+
(arg_count - 1, Load(bcx, expr::get_dataptr(bcx, val)))
1084+
};
1085+
let mut field_vals: Vec<ValueRef> = (0..arg_count).map(|ix|
1086+
adt::trans_field_ptr(bcx, &*repr, struct_val, 0, ix)
10811087
).collect();
1088+
1089+
match left_ty.sty {
1090+
ty::ty_struct(def_id, substs) if !type_is_sized(bcx.tcx(), left_ty) => {
1091+
// The last field is technically unsized
1092+
// but since we can only ever match that field behind
1093+
// a reference we construct a fat ptr here
1094+
let fields = ty::lookup_struct_fields(bcx.tcx(), def_id);
1095+
let unsized_ty = fields.iter().last().map(|field| {
1096+
let fty = ty::lookup_field_type(bcx.tcx(), def_id, field.id, substs);
1097+
monomorphize::normalize_associated_type(bcx.tcx(), &fty)
1098+
}).unwrap();
1099+
let llty = type_of::type_of(bcx.ccx(), unsized_ty);
1100+
let scratch = alloca_no_lifetime(bcx, llty, "__struct_field_fat_ptr");
1101+
let data = adt::trans_field_ptr(bcx, &*repr, struct_val, 0, arg_count);
1102+
let len = Load(bcx, expr::get_len(bcx, val));
1103+
Store(bcx, data, expr::get_dataptr(bcx, scratch));
1104+
Store(bcx, len, expr::get_len(bcx, scratch));
1105+
field_vals.push(scratch);
1106+
}
1107+
_ => {}
1108+
}
10821109
Some(field_vals)
10831110
} else if any_uniq_pat(m, col) || any_region_pat(m, col) {
10841111
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)