From 70fe20a69827a2b1abfef338c83f9ec9be7c9376 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Wed, 22 Oct 2014 21:23:26 +0200 Subject: [PATCH] Fix codegen breaking aliasing rules for functions with sret results This reverts commit a0ec902e239b2219edf1a18b036dd32c18d3be42 "Avoid unnecessary temporary on assignments". Leaving out the temporary for the functions return value can lead to a situation that conflicts with rust's aliasing rules. Given this: ````rust fn func(f: &mut Foo) -> Foo { /* ... */ } fn bar() { let mut foo = Foo { /* ... */ }; foo = func(&mut foo); } ```` We effectively get two mutable references to the same variable `foo` at the same time. One for the parameter `f`, and one for the hidden out-pointer. So we can't just `trans_into` the destination directly, but must use `trans` to get a new temporary slot from which the result can be copied. --- src/librustc/middle/trans/expr.rs | 4 +-- src/test/run-pass/out-pointer-aliasing.rs | 30 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/out-pointer-aliasing.rs diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index d638286a9c5b..a7b9c137331b 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -940,6 +940,7 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, controlflow::trans_loop(bcx, expr.id, &**body) } ast::ExprAssign(ref dst, ref src) => { + let src_datum = unpack_datum!(bcx, trans(bcx, &**src)); let dst_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &**dst, "assign")); if ty::type_needs_drop(bcx.tcx(), dst_datum.ty) { @@ -960,7 +961,6 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // We could avoid this intermediary with some analysis // to determine whether `dst` may possibly own `src`. debuginfo::set_source_location(bcx.fcx, expr.id, expr.span); - let src_datum = unpack_datum!(bcx, trans(bcx, &**src)); let src_datum = unpack_datum!( bcx, src_datum.to_rvalue_datum(bcx, "ExprAssign")); bcx = glue::drop_ty(bcx, @@ -969,7 +969,7 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, Some(NodeInfo { id: expr.id, span: expr.span })); src_datum.store_to(bcx, dst_datum.val) } else { - trans_into(bcx, &**src, SaveIn(dst_datum.to_llref())) + src_datum.store_to(bcx, dst_datum.val) } } ast::ExprAssignOp(op, ref dst, ref src) => { diff --git a/src/test/run-pass/out-pointer-aliasing.rs b/src/test/run-pass/out-pointer-aliasing.rs new file mode 100644 index 000000000000..2a44df7a1b56 --- /dev/null +++ b/src/test/run-pass/out-pointer-aliasing.rs @@ -0,0 +1,30 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Foo { + f1: int, + _f2: int, +} + +#[inline(never)] +pub fn foo(f: &mut Foo) -> Foo { + let ret = *f; + f.f1 = 0; + ret +} + +pub fn main() { + let mut f = Foo { + f1: 8, + _f2: 9, + }; + f = foo(&mut f); + assert_eq!(f.f1, 8); +}