auto merge of #11585 : nikomatsakis/rust/issue-3511-rvalue-lifetimes, r=pcwalton
Major changes: - Define temporary scopes in a syntax-based way that basically defaults to the innermost statement or conditional block, except for in a `let` initializer, where we default to the innermost block. Rules are documented in the code, but not in the manual (yet). See new test run-pass/cleanup-value-scopes.rs for examples. - Refactors Datum to better define cleanup roles. - Refactor cleanup scopes to not be tied to basic blocks, permitting us to have a very large number of scopes (one per AST node). - Introduce nascent documentation in trans/doc.rs covering datums and cleanup in a more comprehensive way. r? @pcwalton
This commit is contained in:
commit
4098327b1f
72 changed files with 5064 additions and 3754 deletions
22
src/test/compile-fail/borrowck-borrow-from-temporary.rs
Normal file
22
src/test/compile-fail/borrowck-borrow-from-temporary.rs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// 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 <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.
|
||||
|
||||
// Test lifetimes are linked properly when we take reference
|
||||
// to interior.
|
||||
|
||||
struct Foo(int);
|
||||
|
||||
fn foo() -> &int {
|
||||
let &Foo(ref x) = &Foo(3); //~ ERROR borrowed value does not live long enough
|
||||
x
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
// 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 <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.
|
||||
|
||||
// Test that assignments to an `&mut` pointer which is found in a
|
||||
// borrowed (but otherwise non-aliasable) location is illegal.
|
||||
|
||||
struct S<'a> {
|
||||
pointer: &'a mut int
|
||||
}
|
||||
|
||||
fn copy_borrowed_ptr<'a,'b>(p: &'a mut S<'b>) -> S<'b> {
|
||||
S { pointer: &mut *p.pointer } //~ ERROR lifetime of `p` is too short to guarantee its contents can be safely reborrowed
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut x = 1;
|
||||
|
||||
{
|
||||
let mut y = S { pointer: &mut x };
|
||||
let z = copy_borrowed_ptr(&mut y);
|
||||
*y.pointer += 1;
|
||||
*z.pointer += 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
// Copyright 2012 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.
|
||||
|
||||
// Tests that rvalue lifetimes is limited to the enclosing trans
|
||||
// cleanup scope. It is unclear that this is the correct lifetime for
|
||||
// rvalues, but that's what it is right now.
|
||||
|
||||
struct Counter {
|
||||
value: uint
|
||||
}
|
||||
|
||||
impl Counter {
|
||||
fn new(v: uint) -> Counter {
|
||||
Counter {value: v}
|
||||
}
|
||||
|
||||
fn inc<'a>(&'a mut self) -> &'a mut Counter {
|
||||
self.value += 1;
|
||||
self
|
||||
}
|
||||
|
||||
fn get(&self) -> uint {
|
||||
self.value
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let v = Counter::new(22).inc().inc().get();
|
||||
//~^ ERROR borrowed value does not live long enough
|
||||
assert_eq!(v, 24);;
|
||||
}
|
||||
45
src/test/compile-fail/cleanup-rvalue-scopes-cf.rs
Normal file
45
src/test/compile-fail/cleanup-rvalue-scopes-cf.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
// 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 <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.
|
||||
|
||||
// Test that the borrow checker prevents pointers to temporaries
|
||||
// with statement lifetimes from escaping.
|
||||
|
||||
#[feature(macro_rules)];
|
||||
|
||||
use std::ops::Drop;
|
||||
|
||||
static mut FLAGS: u64 = 0;
|
||||
|
||||
struct Box<T> { f: T }
|
||||
struct AddFlags { bits: u64 }
|
||||
|
||||
fn AddFlags(bits: u64) -> AddFlags {
|
||||
AddFlags { bits: bits }
|
||||
}
|
||||
|
||||
fn arg<'a>(x: &'a AddFlags) -> &'a AddFlags {
|
||||
x
|
||||
}
|
||||
|
||||
impl AddFlags {
|
||||
fn get<'a>(&'a self) -> &'a AddFlags {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let _x = arg(&AddFlags(1)); //~ ERROR value does not live long enough
|
||||
let _x = AddFlags(1).get(); //~ ERROR value does not live long enough
|
||||
let _x = &*arg(&AddFlags(1)); //~ ERROR value does not live long enough
|
||||
let ref _x = *arg(&AddFlags(1)); //~ ERROR value does not live long enough
|
||||
let &ref _x = arg(&AddFlags(1)); //~ ERROR value does not live long enough
|
||||
let _x = AddFlags(1).get(); //~ ERROR value does not live long enough
|
||||
let Box { f: _x } = Box { f: AddFlags(1).get() }; //~ ERROR value does not live long enough
|
||||
}
|
||||
|
|
@ -196,13 +196,13 @@ fn main() {
|
|||
let Unit(ii) = Unit(51);
|
||||
|
||||
// univariant enum with ref binding
|
||||
let Unit(ref jj) = Unit(52);
|
||||
let &Unit(ref jj) = &Unit(52);
|
||||
|
||||
// tuple struct
|
||||
let TupleStruct(kk, ll) = TupleStruct(53.0, 54);
|
||||
let &TupleStruct(kk, ll) = &TupleStruct(53.0, 54);
|
||||
|
||||
// tuple struct with ref binding
|
||||
let TupleStruct(mm, ref nn) = TupleStruct(55.0, 56);
|
||||
let &TupleStruct(mm, ref nn) = &TupleStruct(55.0, 56);
|
||||
|
||||
zzz();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,15 @@ impl Counter {
|
|||
Counter {value: v}
|
||||
}
|
||||
|
||||
fn inc<'a>(&'a mut self) -> &'a mut Counter {
|
||||
self.value += 1;
|
||||
self
|
||||
}
|
||||
|
||||
fn get(&self) -> uint {
|
||||
self.value
|
||||
}
|
||||
|
||||
fn get_and_inc(&mut self) -> uint {
|
||||
let v = self.value;
|
||||
self.value += 1;
|
||||
|
|
@ -27,4 +36,7 @@ impl Counter {
|
|||
pub fn main() {
|
||||
let v = Counter::new(22).get_and_inc();
|
||||
assert_eq!(v, 22);
|
||||
|
||||
let v = Counter::new(22).inc().inc().get();
|
||||
assert_eq!(v, 24);;
|
||||
}
|
||||
|
|
|
|||
43
src/test/run-pass/cleanup-arm-conditional.rs
Normal file
43
src/test/run-pass/cleanup-arm-conditional.rs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// 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 <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.
|
||||
|
||||
// Test that cleanup scope for temporaries created in a match
|
||||
// arm is confined to the match arm itself.
|
||||
|
||||
use std::{os, run};
|
||||
use std::io::process;
|
||||
|
||||
struct Test { x: int }
|
||||
|
||||
impl Test {
|
||||
fn get_x(&self) -> Option<~int> {
|
||||
Some(~self.x)
|
||||
}
|
||||
}
|
||||
|
||||
fn do_something(t: &Test) -> int {
|
||||
|
||||
// The cleanup scope for the result of `t.get_x()` should be the
|
||||
// arm itself and not the match, otherwise we'll (potentially) get
|
||||
// a crash trying to free an uninitialized stack slot.
|
||||
|
||||
match t {
|
||||
&Test { x: 2 } if t.get_x().is_some() => {
|
||||
t.x * 2
|
||||
}
|
||||
_ => { 22 }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let t = Test { x: 1 };
|
||||
do_something(&t);
|
||||
}
|
||||
|
||||
70
src/test/run-pass/cleanup-rvalue-for-scope.rs
Normal file
70
src/test/run-pass/cleanup-rvalue-for-scope.rs
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// 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 <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.
|
||||
|
||||
// Test that the lifetime of rvalues in for loops is extended
|
||||
// to the for loop itself.
|
||||
|
||||
#[feature(macro_rules)];
|
||||
|
||||
use std::ops::Drop;
|
||||
|
||||
static mut FLAGS: u64 = 0;
|
||||
|
||||
struct Box<T> { f: T }
|
||||
struct AddFlags { bits: u64 }
|
||||
|
||||
fn AddFlags(bits: u64) -> AddFlags {
|
||||
AddFlags { bits: bits }
|
||||
}
|
||||
|
||||
fn arg(exp: u64, _x: &AddFlags) {
|
||||
check_flags(exp);
|
||||
}
|
||||
|
||||
fn pass<T>(v: T) -> T {
|
||||
v
|
||||
}
|
||||
|
||||
fn check_flags(exp: u64) {
|
||||
unsafe {
|
||||
let x = FLAGS;
|
||||
FLAGS = 0;
|
||||
println!("flags {}, expected {}", x, exp);
|
||||
assert_eq!(x, exp);
|
||||
}
|
||||
}
|
||||
|
||||
impl AddFlags {
|
||||
fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags {
|
||||
check_flags(exp);
|
||||
self
|
||||
}
|
||||
|
||||
fn bits(&self) -> u64 {
|
||||
self.bits
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AddFlags {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
FLAGS = FLAGS + self.bits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
// The array containing [AddFlags] should not be dropped until
|
||||
// after the for loop:
|
||||
for x in [AddFlags(1)].iter() {
|
||||
check_flags(0);
|
||||
}
|
||||
check_flags(1);
|
||||
}
|
||||
137
src/test/run-pass/cleanup-rvalue-scopes.rs
Normal file
137
src/test/run-pass/cleanup-rvalue-scopes.rs
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
// 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 <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.
|
||||
|
||||
// Test that destructors for rvalue temporaries run either at end of
|
||||
// statement or end of block, as appropriate given the temporary
|
||||
// lifetime rules.
|
||||
|
||||
#[feature(macro_rules)];
|
||||
|
||||
use std::ops::Drop;
|
||||
|
||||
static mut FLAGS: u64 = 0;
|
||||
|
||||
struct Box<T> { f: T }
|
||||
struct AddFlags { bits: u64 }
|
||||
|
||||
fn AddFlags(bits: u64) -> AddFlags {
|
||||
AddFlags { bits: bits }
|
||||
}
|
||||
|
||||
fn arg(exp: u64, _x: &AddFlags) {
|
||||
check_flags(exp);
|
||||
}
|
||||
|
||||
fn pass<T>(v: T) -> T {
|
||||
v
|
||||
}
|
||||
|
||||
fn check_flags(exp: u64) {
|
||||
unsafe {
|
||||
let x = FLAGS;
|
||||
FLAGS = 0;
|
||||
println!("flags {}, expected {}", x, exp);
|
||||
assert_eq!(x, exp);
|
||||
}
|
||||
}
|
||||
|
||||
impl AddFlags {
|
||||
fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags {
|
||||
check_flags(exp);
|
||||
self
|
||||
}
|
||||
|
||||
fn bits(&self) -> u64 {
|
||||
self.bits
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for AddFlags {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
FLAGS = FLAGS + self.bits;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! end_of_block(
|
||||
($pat:pat, $expr:expr) => (
|
||||
{
|
||||
println!("end_of_block({})", stringify!({let $pat = $expr;}));
|
||||
|
||||
{
|
||||
// Destructor here does not run until exit from the block.
|
||||
let $pat = $expr;
|
||||
check_flags(0);
|
||||
}
|
||||
check_flags(1);
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
macro_rules! end_of_stmt(
|
||||
($pat:pat, $expr:expr) => (
|
||||
{
|
||||
println!("end_of_stmt({})", stringify!($expr));
|
||||
|
||||
{
|
||||
// Destructor here run after `let` statement
|
||||
// terminates.
|
||||
let $pat = $expr;
|
||||
check_flags(1);
|
||||
}
|
||||
|
||||
check_flags(0);
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
pub fn main() {
|
||||
|
||||
// In all these cases, we trip over the rules designed to cover
|
||||
// the case where we are taking addr of rvalue and storing that
|
||||
// addr into a stack slot, either via `let ref` or via a `&` in
|
||||
// the initializer.
|
||||
|
||||
end_of_block!(_x, AddFlags(1));
|
||||
end_of_block!(_x, &AddFlags(1));
|
||||
end_of_block!(_x, & &AddFlags(1));
|
||||
end_of_block!(_x, Box { f: AddFlags(1) });
|
||||
end_of_block!(_x, Box { f: &AddFlags(1) });
|
||||
end_of_block!(_x, Box { f: &AddFlags(1) });
|
||||
end_of_block!(_x, pass(AddFlags(1)));
|
||||
end_of_block!(ref _x, AddFlags(1));
|
||||
end_of_block!(AddFlags { bits: ref _x }, AddFlags(1));
|
||||
end_of_block!(&AddFlags { bits }, &AddFlags(1));
|
||||
end_of_block!((_, ref _y), (AddFlags(1), 22));
|
||||
end_of_block!(~ref _x, ~AddFlags(1));
|
||||
end_of_block!(~_x, ~AddFlags(1));
|
||||
end_of_block!(_, { { check_flags(0); &AddFlags(1) } });
|
||||
end_of_block!(_, &((Box { f: AddFlags(1) }).f));
|
||||
end_of_block!(_, &(([AddFlags(1)])[0]));
|
||||
end_of_block!(_, &((&~[AddFlags(1)])[0]));
|
||||
|
||||
// LHS does not create a ref binding, so temporary lives as long
|
||||
// as statement, and we do not move the AddFlags out:
|
||||
end_of_stmt!(_, AddFlags(1));
|
||||
end_of_stmt!((_, _), (AddFlags(1), 22));
|
||||
|
||||
// `&` operator appears inside an arg to a function,
|
||||
// so it is not prolonged:
|
||||
end_of_stmt!(ref _x, arg(0, &AddFlags(1)));
|
||||
|
||||
// autoref occurs inside receiver, so temp lifetime is not
|
||||
// prolonged:
|
||||
end_of_stmt!(ref _x, AddFlags(1).check_flags(0).bits());
|
||||
|
||||
// No reference is created on LHS, thus RHS is moved into
|
||||
// a temporary that lives just as long as the statement.
|
||||
end_of_stmt!(AddFlags { bits }, AddFlags(1));
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Test cleanup of rvalue temporary that occurs while `~` construction
|
||||
// is in progress. This scenario revealed a rather terrible bug. The
|
||||
// ingredients are:
|
||||
//
|
||||
// 1. Partial cleanup of `~` is in scope,
|
||||
// 2. cleanup of return value from `get_bar()` is in scope,
|
||||
// 3. do_it() fails.
|
||||
//
|
||||
// This led to a bug because `the top-most frame that was to be
|
||||
// cleaned (which happens to be the partial cleanup of `~`) required
|
||||
// multiple basic blocks, which led to us dropping part of the cleanup
|
||||
// from the top-most frame.
|
||||
//
|
||||
// It's unclear how likely such a bug is to recur, but it seems like a
|
||||
// scenario worth testing.
|
||||
|
||||
use std::task;
|
||||
|
||||
enum Conzabble {
|
||||
Bickwick(Foo)
|
||||
}
|
||||
|
||||
struct Foo { field: ~uint }
|
||||
|
||||
fn do_it(x: &[uint]) -> Foo {
|
||||
fail!()
|
||||
}
|
||||
|
||||
fn get_bar(x: uint) -> ~[uint] { ~[x * 2] }
|
||||
|
||||
pub fn fails() {
|
||||
let x = 2;
|
||||
let mut y = ~[];
|
||||
y.push(~Bickwick(do_it(get_bar(x))));
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
task::try(fails);
|
||||
}
|
||||
30
src/test/run-pass/cleanup-shortcircuit.rs
Normal file
30
src/test/run-pass/cleanup-shortcircuit.rs
Normal file
|
|
@ -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 <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.
|
||||
|
||||
// Test that cleanups for the RHS of shorcircuiting operators work.
|
||||
|
||||
use std::{os, run};
|
||||
use std::io::process;
|
||||
|
||||
pub fn main() {
|
||||
let args = os::args();
|
||||
|
||||
// Here, the rvalue `~"signal"` requires cleanup. Older versions
|
||||
// of the code had a problem that the cleanup scope for this
|
||||
// expression was the end of the `if`, and as the `~"signal"`
|
||||
// expression was never evaluated, we wound up trying to clean
|
||||
// uninitialized memory.
|
||||
|
||||
if args.len() >= 2 && args[1] == ~"signal" {
|
||||
// Raise a segfault.
|
||||
unsafe { *(0 as *mut int) = 0; }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -8,20 +8,22 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[feature(managed_boxes)];
|
||||
use std::cast::transmute;
|
||||
|
||||
mod rusti {
|
||||
extern "rust-intrinsic" {
|
||||
pub fn init<T>() -> T;
|
||||
pub fn move_val_init<T>(dst: &mut T, src: T);
|
||||
pub fn move_val<T>(dst: &mut T, src: T);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
let x = @1;
|
||||
let mut y = @2;
|
||||
rusti::move_val(&mut y, x);
|
||||
let x = ~1;
|
||||
let mut y = rusti::init();
|
||||
let mut z: *uint = transmute(&x);
|
||||
rusti::move_val_init(&mut y, x);
|
||||
assert_eq!(*y, 1);
|
||||
assert_eq!(*z, 0); // `x` is nulled out, not directly visible
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@ pub fn main () {
|
|||
|
||||
let config = process::ProcessConfig {
|
||||
program : args[0].as_slice(),
|
||||
args : [~"child"],
|
||||
args : &[~"child"],
|
||||
env : None,
|
||||
cwd : None,
|
||||
io : []
|
||||
io : &[]
|
||||
};
|
||||
|
||||
let mut p = process::Process::new(config).unwrap();
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ struct Thing2<'a> {
|
|||
|
||||
pub fn main() {
|
||||
let _t1_fixed = Thing1 {
|
||||
baz: [],
|
||||
baz: &[],
|
||||
bar: ~32,
|
||||
};
|
||||
let _t1_uniq = Thing1 {
|
||||
Thing1 {
|
||||
baz: ~[],
|
||||
bar: ~32,
|
||||
};
|
||||
|
|
@ -40,10 +40,10 @@ pub fn main() {
|
|||
bar: ~32,
|
||||
};
|
||||
let _t2_fixed = Thing2 {
|
||||
baz: [],
|
||||
baz: &[],
|
||||
bar: 32,
|
||||
};
|
||||
let _t2_uniq = Thing2 {
|
||||
Thing2 {
|
||||
baz: ~[],
|
||||
bar: 32,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ struct Triple { x: int, y: int, z: int }
|
|||
fn test(x: bool, foo: @Triple) -> int {
|
||||
let bar = foo;
|
||||
let mut y: @Triple;
|
||||
y = bar;
|
||||
if x { y = bar; } else { y = @Triple{x: 4, y: 5, z: 6}; }
|
||||
return y.y;
|
||||
}
|
||||
|
|
|
|||
19
src/test/run-pass/regions-dependent-let-ref.rs
Normal file
19
src/test/run-pass/regions-dependent-let-ref.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// 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 <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.
|
||||
|
||||
// Test lifetimes are linked properly when we take reference
|
||||
// to interior.
|
||||
|
||||
struct Foo(int);
|
||||
pub fn main() {
|
||||
// Here the lifetime of the `&` should be at least the
|
||||
// block, since a ref binding is created to the interior.
|
||||
let &Foo(ref _x) = &Foo(3);
|
||||
}
|
||||
24
src/test/run-pass/uninit-empty-types.rs
Normal file
24
src/test/run-pass/uninit-empty-types.rs
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// 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 <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.
|
||||
|
||||
// Test the uninit() construct returning various empty types.
|
||||
|
||||
use std::vec;
|
||||
use std::unstable::intrinsics;
|
||||
|
||||
#[deriving(Clone)]
|
||||
struct Foo;
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
let _x: Foo = intrinsics::uninit();
|
||||
let _x: [Foo, ..2] = intrinsics::uninit();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue