Skip to content

Commit 3d9206f

Browse files
committed
auto merge of #16081 : luqmana/rust/nr, r=pcwalton
Fixes #15763
2 parents b495933 + b3337a9 commit 3d9206f

File tree

8 files changed

+177
-42
lines changed

8 files changed

+177
-42
lines changed

src/librustc/middle/trans/base.rs

+43-22
Original file line numberDiff line numberDiff line change
@@ -1210,16 +1210,23 @@ pub fn arrayalloca(cx: &Block, ty: Type, v: ValueRef) -> ValueRef {
12101210
p
12111211
}
12121212

1213-
// Creates and returns space for, or returns the argument representing, the
1214-
// slot where the return value of the function must go.
1215-
pub fn make_return_pointer(fcx: &FunctionContext, output_type: ty::t)
1216-
-> ValueRef {
1213+
// Creates the alloca slot which holds the pointer to the slot for the final return value
1214+
pub fn make_return_slot_pointer(fcx: &FunctionContext, output_type: ty::t) -> ValueRef {
1215+
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
1216+
1217+
// Let's create the stack slot
1218+
let slot = AllocaFcx(fcx, lloutputtype.ptr_to(), "llretslotptr");
1219+
1220+
// and if we're using an out pointer, then store that in our newly made slot
12171221
if type_of::return_uses_outptr(fcx.ccx, output_type) {
1218-
get_param(fcx.llfn, 0)
1219-
} else {
1220-
let lloutputtype = type_of::type_of(fcx.ccx, output_type);
1221-
AllocaFcx(fcx, lloutputtype, "__make_return_pointer")
1222+
let outptr = get_param(fcx.llfn, 0);
1223+
1224+
let b = fcx.ccx.builder();
1225+
b.position_before(fcx.alloca_insert_pt.get().unwrap());
1226+
b.store(outptr, slot);
12221227
}
1228+
1229+
slot
12231230
}
12241231

12251232
// NB: must keep 4 fns in sync:
@@ -1258,7 +1265,7 @@ pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext,
12581265
let mut fcx = FunctionContext {
12591266
llfn: llfndecl,
12601267
llenv: None,
1261-
llretptr: Cell::new(None),
1268+
llretslotptr: Cell::new(None),
12621269
alloca_insert_pt: Cell::new(None),
12631270
llreturn: Cell::new(None),
12641271
personality: Cell::new(None),
@@ -1303,12 +1310,12 @@ pub fn init_function<'a>(fcx: &'a FunctionContext<'a>,
13031310

13041311
if !return_type_is_void(fcx.ccx, substd_output_type) {
13051312
// If the function returns nil/bot, there is no real return
1306-
// value, so do not set `llretptr`.
1313+
// value, so do not set `llretslotptr`.
13071314
if !skip_retptr || fcx.caller_expects_out_pointer {
1308-
// Otherwise, we normally allocate the llretptr, unless we
1315+
// Otherwise, we normally allocate the llretslotptr, unless we
13091316
// have been instructed to skip it for immediate return
13101317
// values.
1311-
fcx.llretptr.set(Some(make_return_pointer(fcx, substd_output_type)));
1318+
fcx.llretslotptr.set(Some(make_return_slot_pointer(fcx, substd_output_type)));
13121319
}
13131320
}
13141321

@@ -1533,12 +1540,12 @@ pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
15331540

15341541
// Builds the return block for a function.
15351542
pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
1536-
// Return the value if this function immediate; otherwise, return void.
1537-
if fcx.llretptr.get().is_none() || fcx.caller_expects_out_pointer {
1543+
if fcx.llretslotptr.get().is_none() {
15381544
return RetVoid(ret_cx);
15391545
}
15401546

1541-
let retptr = Value(fcx.llretptr.get().unwrap());
1547+
let retslot = Load(ret_cx, fcx.llretslotptr.get().unwrap());
1548+
let retptr = Value(retslot);
15421549
let retval = match retptr.get_dominating_store(ret_cx) {
15431550
// If there's only a single store to the ret slot, we can directly return
15441551
// the value that was stored and omit the store and the alloca
@@ -1557,10 +1564,15 @@ pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block, retty: ty::t) {
15571564
}
15581565
}
15591566
// Otherwise, load the return value from the ret slot
1560-
None => load_ty(ret_cx, fcx.llretptr.get().unwrap(), retty)
1567+
None => load_ty(ret_cx, retslot, retty)
15611568
};
15621569

1563-
Ret(ret_cx, retval);
1570+
if fcx.caller_expects_out_pointer {
1571+
store_ty(ret_cx, retval, get_param(fcx.llfn, 0), retty);
1572+
RetVoid(ret_cx);
1573+
} else {
1574+
Ret(ret_cx, retval);
1575+
}
15641576
}
15651577

15661578
#[deriving(Clone, Eq, PartialEq)]
@@ -1658,10 +1670,10 @@ pub fn trans_closure(ccx: &CrateContext,
16581670
// emitting should be enabled.
16591671
debuginfo::start_emitting_source_locations(&fcx);
16601672

1661-
let dest = match fcx.llretptr.get() {
1662-
Some(e) => {expr::SaveIn(e)}
1673+
let dest = match fcx.llretslotptr.get() {
1674+
Some(_) => expr::SaveIn(alloca(bcx, type_of::type_of(bcx.ccx(), block_ty), "iret_slot")),
16631675
None => {
1664-
assert!(type_is_zero_size(bcx.ccx(), block_ty))
1676+
assert!(type_is_zero_size(bcx.ccx(), block_ty));
16651677
expr::Ignore
16661678
}
16671679
};
@@ -1672,6 +1684,13 @@ pub fn trans_closure(ccx: &CrateContext,
16721684
// (trans_block, trans_expr, et cetera).
16731685
bcx = controlflow::trans_block(bcx, body, dest);
16741686

1687+
match dest {
1688+
expr::SaveIn(slot) => {
1689+
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
1690+
}
1691+
_ => {}
1692+
}
1693+
16751694
match fcx.llreturn.get() {
16761695
Some(_) => {
16771696
Br(bcx, fcx.return_exit_block());
@@ -1841,16 +1860,18 @@ fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
18411860
let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
18421861

18431862
if !type_is_zero_size(fcx.ccx, result_ty) {
1863+
let dest = alloca(bcx, type_of::type_of(bcx.ccx(), result_ty), "eret_slot");
18441864
let repr = adt::represent_type(ccx, result_ty);
18451865
for (i, arg_datum) in arg_datums.move_iter().enumerate() {
18461866
let lldestptr = adt::trans_field_ptr(bcx,
18471867
&*repr,
1848-
fcx.llretptr.get().unwrap(),
1868+
dest,
18491869
disr,
18501870
i);
18511871
arg_datum.store_to(bcx, lldestptr);
18521872
}
1853-
adt::trans_set_discr(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
1873+
adt::trans_set_discr(bcx, &*repr, dest, disr);
1874+
Store(bcx, dest, fcx.llretslotptr.get().unwrap());
18541875
}
18551876

18561877
finish_fn(&fcx, bcx, result_ty);

src/librustc/middle/trans/callee.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,10 @@ pub fn trans_unboxing_shim(bcx: &Block,
389389
for i in range(1, arg_types.len()) {
390390
llshimmedargs.push(get_param(fcx.llfn, fcx.arg_pos(i) as u32));
391391
}
392+
let dest = match fcx.llretslotptr.get() {
393+
Some(_) => Some(expr::SaveIn(alloca(bcx, type_of::type_of(ccx, return_type), "ret_slot"))),
394+
None => None
395+
};
392396
bcx = trans_call_inner(bcx,
393397
None,
394398
function_type,
@@ -399,10 +403,13 @@ pub fn trans_unboxing_shim(bcx: &Block,
399403
}
400404
},
401405
ArgVals(llshimmedargs.as_slice()),
402-
match fcx.llretptr.get() {
403-
None => None,
404-
Some(llretptr) => Some(expr::SaveIn(llretptr)),
405-
}).bcx;
406+
dest).bcx;
407+
match dest {
408+
Some(expr::SaveIn(slot)) => {
409+
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
410+
}
411+
_ => {}
412+
}
406413

407414
bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
408415
finish_fn(&fcx, bcx, return_type);

src/librustc/middle/trans/closure.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -582,16 +582,16 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
582582
ty::ty_fn_args(closure_ty)
583583
.as_slice());
584584
let mut llargs = Vec::new();
585-
match fcx.llretptr.get() {
586-
Some(llretptr) => {
587-
llargs.push(llretptr);
585+
match fcx.llretslotptr.get() {
586+
Some(llretslotptr) => {
587+
llargs.push(Load(bcx, llretslotptr));
588588
}
589589
None => {}
590590
}
591591
llargs.extend(args.iter().map(|arg| arg.val));
592592

593593
let retval = Call(bcx, fn_ptr, llargs.as_slice(), None);
594-
if type_is_zero_size(ccx, f.sig.output) || fcx.llretptr.get().is_some() {
594+
if type_is_zero_size(ccx, f.sig.output) || fcx.llretslotptr.get().is_some() {
595595
RetVoid(bcx);
596596
} else {
597597
Ret(bcx, retval);

src/librustc/middle/trans/common.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -239,11 +239,11 @@ pub struct FunctionContext<'a> {
239239
// The environment argument in a closure.
240240
pub llenv: Option<ValueRef>,
241241

242-
// The place to store the return value. If the return type is immediate,
243-
// this is an alloca in the function. Otherwise, it's the hidden first
244-
// parameter to the function. After function construction, this should
245-
// always be Some.
246-
pub llretptr: Cell<Option<ValueRef>>,
242+
// A pointer to where to store the return value. If the return type is
243+
// immediate, this points to an alloca in the function. Otherwise, it's a
244+
// pointer to the hidden first parameter of the function. After function
245+
// construction, this should always be Some.
246+
pub llretslotptr: Cell<Option<ValueRef>>,
247247

248248
// These pub elements: "hoisted basic blocks" containing
249249
// administrative activities that have to happen in only one place in
@@ -258,8 +258,8 @@ pub struct FunctionContext<'a> {
258258
pub personality: Cell<Option<ValueRef>>,
259259

260260
// True if the caller expects this fn to use the out pointer to
261-
// return. Either way, your code should write into llretptr, but if
262-
// this value is false, llretptr will be a local alloca.
261+
// return. Either way, your code should write into the slot llretslotptr
262+
// points to, but if this value is false, that slot will be a local alloca.
263263
pub caller_expects_out_pointer: bool,
264264

265265
// Maps arguments to allocas created for them in llallocas.

src/librustc/middle/trans/controlflow.rs

+13-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use middle::trans::debuginfo;
2626
use middle::trans::expr;
2727
use middle::trans::meth;
2828
use middle::trans::type_::Type;
29+
use middle::trans::type_of;
2930
use middle::ty;
3031
use middle::typeck::MethodCall;
3132
use util::ppaux::Repr;
@@ -462,13 +463,22 @@ pub fn trans_ret<'a>(bcx: &'a Block<'a>,
462463
let _icx = push_ctxt("trans_ret");
463464
let fcx = bcx.fcx;
464465
let mut bcx = bcx;
465-
let dest = match bcx.fcx.llretptr.get() {
466-
None => expr::Ignore,
467-
Some(retptr) => expr::SaveIn(retptr),
466+
let dest = match (fcx.llretslotptr.get(), e) {
467+
(Some(_), Some(e)) => {
468+
let ret_ty = expr_ty(bcx, &*e);
469+
expr::SaveIn(alloca(bcx, type_of::type_of(bcx.ccx(), ret_ty), "ret_slot"))
470+
}
471+
_ => expr::Ignore,
468472
};
469473
match e {
470474
Some(x) => {
471475
bcx = expr::trans_into(bcx, &*x, dest);
476+
match dest {
477+
expr::SaveIn(slot) => {
478+
Store(bcx, slot, fcx.llretslotptr.get().unwrap());
479+
}
480+
_ => {}
481+
}
472482
}
473483
_ => {}
474484
}

src/librustc/middle/trans/reflect.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,9 @@ impl<'a, 'b> Reflector<'a, 'b> {
321321
let arg = get_param(llfdecl, fcx.arg_pos(0u) as c_uint);
322322
let arg = BitCast(bcx, arg, llptrty);
323323
let ret = adt::trans_get_discr(bcx, &*repr, arg, Some(Type::i64(ccx)));
324-
Store(bcx, ret, fcx.llretptr.get().unwrap());
324+
let ret_alloca = alloca(bcx, Type::i64(ccx), "ret_slot");
325+
Store(bcx, ret, ret_alloca);
326+
Store(bcx, ret_alloca, fcx.llretslotptr.get().unwrap());
325327
match fcx.llreturn.get() {
326328
Some(llreturn) => Br(bcx, llreturn),
327329
None => {}

src/libserialize/json.rs

-1
Original file line numberDiff line numberDiff line change
@@ -2795,7 +2795,6 @@ mod tests {
27952795
}
27962796
}
27972797
#[test]
2798-
#[ignore] // FIXME(#15763)
27992798
fn test_decode_errors_struct() {
28002799
check_err::<DecodeStruct>("[]", ExpectedError("Object".to_string(), "[]".to_string()));
28012800
check_err::<DecodeStruct>("{\"x\": true, \"y\": true, \"z\": \"\", \"w\": []}",

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

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
// Copyright 2014 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+
12+
#[deriving(PartialEq, Show)]
13+
struct Bar {
14+
x: int
15+
}
16+
impl Drop for Bar {
17+
fn drop(&mut self) {
18+
assert_eq!(self.x, 22);
19+
}
20+
}
21+
22+
#[deriving(PartialEq, Show)]
23+
struct Foo {
24+
x: Bar,
25+
a: int
26+
}
27+
28+
fn foo() -> Result<Foo, int> {
29+
return Ok(Foo {
30+
x: Bar { x: 22 },
31+
a: return Err(32)
32+
});
33+
}
34+
35+
fn baz() -> Result<Foo, int> {
36+
Ok(Foo {
37+
x: Bar { x: 22 },
38+
a: return Err(32)
39+
})
40+
}
41+
42+
// explicit immediate return
43+
fn aa() -> int {
44+
return 3;
45+
}
46+
47+
// implicit immediate return
48+
fn bb() -> int {
49+
3
50+
}
51+
52+
// implicit outptr return
53+
fn cc() -> Result<int, int> {
54+
Ok(3)
55+
}
56+
57+
// explicit outptr return
58+
fn dd() -> Result<int, int> {
59+
return Ok(3);
60+
}
61+
62+
trait A {
63+
fn aaa(self) -> int {
64+
3
65+
}
66+
fn bbb(self) -> int {
67+
return 3;
68+
}
69+
fn ccc(self) -> Result<int, int> {
70+
Ok(3)
71+
}
72+
fn ddd(self) -> Result<int, int> {
73+
return Ok(3);
74+
}
75+
}
76+
77+
impl A for int {}
78+
79+
fn main() {
80+
assert_eq!(foo(), Err(32));
81+
assert_eq!(baz(), Err(32));
82+
83+
assert_eq!(aa(), 3);
84+
assert_eq!(bb(), 3);
85+
assert_eq!(cc().unwrap(), 3);
86+
assert_eq!(dd().unwrap(), 3);
87+
88+
let i = box 32i as Box<A>;
89+
assert_eq!(i.aaa(), 3);
90+
let i = box 32i as Box<A>;
91+
assert_eq!(i.bbb(), 3);
92+
let i = box 32i as Box<A>;
93+
assert_eq!(i.ccc().unwrap(), 3);
94+
let i = box 32i as Box<A>;
95+
assert_eq!(i.ddd().unwrap(), 3);
96+
}

0 commit comments

Comments
 (0)