]> git.proxmox.com Git - rustc.git/blob - src/test/run-pass/cleanup-rvalue-scopes.rs
New upstream version 1.19.0+dfsg1
[rustc.git] / src / test / run-pass / cleanup-rvalue-scopes.rs
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 // Test that destructors for rvalue temporaries run either at end of
12 // statement or end of block, as appropriate given the temporary
13 // lifetime rules.
14
15 #![feature(box_patterns)]
16 #![feature(box_syntax)]
17
18 use std::ops::Drop;
19
20 static mut FLAGS: u64 = 0;
21
22 struct Box<T> { f: T }
23 struct AddFlags { bits: u64 }
24
25 fn AddFlags(bits: u64) -> AddFlags {
26 AddFlags { bits: bits }
27 }
28
29 fn arg(exp: u64, _x: &AddFlags) {
30 check_flags(exp);
31 }
32
33 fn pass<T>(v: T) -> T {
34 v
35 }
36
37 fn check_flags(exp: u64) {
38 unsafe {
39 let x = FLAGS;
40 FLAGS = 0;
41 println!("flags {}, expected {}", x, exp);
42 assert_eq!(x, exp);
43 }
44 }
45
46 impl AddFlags {
47 fn check_flags<'a>(&'a self, exp: u64) -> &'a AddFlags {
48 check_flags(exp);
49 self
50 }
51
52 fn bits(&self) -> u64 {
53 self.bits
54 }
55 }
56
57 impl Drop for AddFlags {
58 fn drop(&mut self) {
59 unsafe {
60 FLAGS = FLAGS + self.bits;
61 }
62 }
63 }
64
65 macro_rules! end_of_block {
66 ($pat:pat, $expr:expr) => (
67 {
68 println!("end_of_block({})", stringify!({let $pat = $expr;}));
69
70 {
71 // Destructor here does not run until exit from the block.
72 let $pat = $expr;
73 check_flags(0);
74 }
75 check_flags(1);
76 }
77 )
78 }
79
80 macro_rules! end_of_stmt {
81 ($pat:pat, $expr:expr) => (
82 {
83 println!("end_of_stmt({})", stringify!($expr));
84
85 {
86 // Destructor here run after `let` statement
87 // terminates.
88 let $pat = $expr;
89 check_flags(1);
90 }
91
92 check_flags(0);
93 }
94 )
95 }
96
97 pub fn main() {
98
99 // In all these cases, we trip over the rules designed to cover
100 // the case where we are taking addr of rvalue and storing that
101 // addr into a stack slot, either via `let ref` or via a `&` in
102 // the initializer.
103
104 end_of_block!(_x, AddFlags(1));
105 end_of_block!(_x, &AddFlags(1));
106 end_of_block!(_x, & &AddFlags(1));
107 end_of_block!(_x, Box { f: AddFlags(1) });
108 end_of_block!(_x, Box { f: &AddFlags(1) });
109 end_of_block!(_x, Box { f: &AddFlags(1) });
110 end_of_block!(_x, pass(AddFlags(1)));
111 end_of_block!(ref _x, AddFlags(1));
112 end_of_block!(AddFlags { bits: ref _x }, AddFlags(1));
113 end_of_block!(&AddFlags { bits }, &AddFlags(1));
114 end_of_block!((_, ref _y), (AddFlags(1), 22));
115 end_of_block!(box ref _x, box AddFlags(1));
116 end_of_block!(box _x, box AddFlags(1));
117 end_of_block!(_, { { check_flags(0); &AddFlags(1) } });
118 end_of_block!(_, &((Box { f: AddFlags(1) }).f));
119 end_of_block!(_, &(([AddFlags(1)])[0]));
120
121 // LHS does not create a ref binding, so temporary lives as long
122 // as statement, and we do not move the AddFlags out:
123 end_of_stmt!(_, AddFlags(1));
124 end_of_stmt!((_, _), (AddFlags(1), 22));
125
126 // `&` operator appears inside an arg to a function,
127 // so it is not prolonged:
128 end_of_stmt!(ref _x, arg(0, &AddFlags(1)));
129
130 // autoref occurs inside receiver, so temp lifetime is not
131 // prolonged:
132 end_of_stmt!(ref _x, AddFlags(1).check_flags(0).bits());
133
134 // No reference is created on LHS, thus RHS is moved into
135 // a temporary that lives just as long as the statement.
136 end_of_stmt!(AddFlags { bits }, AddFlags(1));
137 }