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