librustc_trans: Handle DST structs in trans::_match.
This commit is contained in:
parent
5574029b68
commit
715605faf9
@ -210,6 +210,7 @@
|
||||
use trans::datum::*;
|
||||
use trans::debuginfo::{self, DebugLoc, ToDebugLoc};
|
||||
use trans::expr::{self, Dest};
|
||||
use trans::monomorphize;
|
||||
use trans::tvec;
|
||||
use trans::type_of;
|
||||
use middle::ty::{self, Ty};
|
||||
@ -1076,9 +1077,39 @@ fn compile_submatch_continue<'a, 'p, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
let adt_vals = if any_irrefutable_adt_pat(bcx.tcx(), m, col) {
|
||||
let repr = adt::represent_type(bcx.ccx(), left_ty);
|
||||
let arg_count = adt::num_args(&*repr, 0);
|
||||
let field_vals: Vec<ValueRef> = (0..arg_count).map(|ix|
|
||||
adt::trans_field_ptr(bcx, &*repr, val, 0, ix)
|
||||
let (arg_count, struct_val) = if type_is_sized(bcx.tcx(), left_ty) {
|
||||
(arg_count, val)
|
||||
} else {
|
||||
// For an unsized ADT (i.e. DST struct), we need to treat
|
||||
// the last field specially: instead of simply passing a
|
||||
// ValueRef pointing to that field, as with all the others,
|
||||
// we skip it and instead construct a 'fat ptr' below.
|
||||
(arg_count - 1, Load(bcx, expr::get_dataptr(bcx, val)))
|
||||
};
|
||||
let mut field_vals: Vec<ValueRef> = (0..arg_count).map(|ix|
|
||||
adt::trans_field_ptr(bcx, &*repr, struct_val, 0, ix)
|
||||
).collect();
|
||||
|
||||
match left_ty.sty {
|
||||
ty::ty_struct(def_id, substs) if !type_is_sized(bcx.tcx(), left_ty) => {
|
||||
// The last field is technically unsized but
|
||||
// since we can only ever match that field behind
|
||||
// a reference we construct a fat ptr here.
|
||||
let fields = ty::lookup_struct_fields(bcx.tcx(), def_id);
|
||||
let unsized_ty = fields.iter().last().map(|field| {
|
||||
let fty = ty::lookup_field_type(bcx.tcx(), def_id, field.id, substs);
|
||||
monomorphize::normalize_associated_type(bcx.tcx(), &fty)
|
||||
}).unwrap();
|
||||
let llty = type_of::type_of(bcx.ccx(), unsized_ty);
|
||||
let scratch = alloca_no_lifetime(bcx, llty, "__struct_field_fat_ptr");
|
||||
let data = adt::trans_field_ptr(bcx, &*repr, struct_val, 0, arg_count);
|
||||
let len = Load(bcx, expr::get_len(bcx, val));
|
||||
Store(bcx, data, expr::get_dataptr(bcx, scratch));
|
||||
Store(bcx, len, expr::get_len(bcx, scratch));
|
||||
field_vals.push(scratch);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Some(field_vals)
|
||||
} else if any_uniq_pat(m, col) || any_region_pat(m, col) {
|
||||
Some(vec!(Load(bcx, val)))
|
||||
|
70
src/test/run-pass/issue-23261.rs
Normal file
70
src/test/run-pass/issue-23261.rs
Normal file
@ -0,0 +1,70 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// Matching on a DST struct should not trigger an LLVM assertion.
|
||||
|
||||
struct Foo<T: ?Sized> {
|
||||
a: i32,
|
||||
inner: T
|
||||
}
|
||||
|
||||
trait Get {
|
||||
fn get(&self) -> i32;
|
||||
}
|
||||
|
||||
impl Get for i32 {
|
||||
fn get(&self) -> i32 {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
fn check_val(val: &Foo<[u8]>) {
|
||||
match *val {
|
||||
Foo { a, .. } => {
|
||||
assert_eq!(a, 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_dst_val(val: &Foo<[u8]>) {
|
||||
match *val {
|
||||
Foo { ref inner, .. } => {
|
||||
assert_eq!(inner, [1, 2, 3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_both(val: &Foo<[u8]>) {
|
||||
match *val {
|
||||
Foo { a, ref inner } => {
|
||||
assert_eq!(a, 32);
|
||||
assert_eq!(inner, [1, 2, 3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_trait_obj(val: &Foo<Get>) {
|
||||
match *val {
|
||||
Foo { a, ref inner } => {
|
||||
assert_eq!(a, 32);
|
||||
assert_eq!(inner.get(), 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo: &Foo<[u8]> = &Foo { a: 32, inner: [1, 2, 3] };
|
||||
check_val(foo);
|
||||
check_dst_val(foo);
|
||||
check_both(foo);
|
||||
|
||||
let foo: &Foo<Get> = &Foo { a: 32, inner: 32 };
|
||||
check_trait_obj(foo);
|
||||
}
|
Loading…
Reference in New Issue
Block a user