1 // rust-lang/rust#45696: This test is checking that we *cannot* return
2 // mutable borrows that would be scribbled over by destructors before
5 // We will explicitly test NLL, and migration modes;
6 // thus we will also skip the automated compare-mode=nll.
8 // revisions: nll migrate
9 // ignore-compare-mode-nll
11 // This test is going to pass in the migrate revision, because the AST-borrowck
12 // accepted this code in the past (see notes below). So we use `#[rustc_error]`
13 // to keep the outcome as an error in all scenarios, and rely on the stderr
14 // files to show what the actual behavior is. (See rust-lang/rust#49855.)
15 #![feature(rustc_attrs)]
17 #![cfg_attr(nll, feature(nll))]
19 struct Scribble<'a>(&'a mut u32);
21 impl<'a> Drop for Scribble<'a> { fn drop(&mut self) { *self.0 = 42; } }
23 // this is okay, in both AST-borrowck and NLL: The `Scribble` here *has*
24 // to strictly outlive `'a`
25 fn borrowed_scribble<'a>(s: &'a mut Scribble) -> &'a mut u32 {
29 // this, by analogy to previous case, is also okay.
30 fn boxed_borrowed_scribble<'a>(s: Box<&'a mut Scribble>) -> &'a mut u32 {
34 // this, by analogy to previous case, is also okay.
35 fn boxed_boxed_borrowed_scribble<'a>(s: Box<Box<&'a mut Scribble>>) -> &'a mut u32 {
39 // this is not okay: in between the time that we take the mutable
40 // borrow and the caller receives it as a return value, the drop of
41 // `s` will scribble on it, violating our aliasing guarantees.
43 // * (Maybe in the future the two-phase borrows system will be
44 // extended to support this case. But for now, it is an error in
45 // NLL, even with two-phase borrows.)
47 // In any case, the AST-borrowck was not smart enough to know that
48 // this should be an error. (Which is perhaps the essence of why
49 // rust-lang/rust#45696 arose in the first place.)
50 fn scribbled<'a>(s: Scribble<'a>) -> &'a mut u32 {
51 &mut *s.0 //[nll]~ ERROR borrow may still be in use when destructor runs [E0713]
52 //[migrate]~^ WARNING borrow may still be in use when destructor runs [E0713]
53 //[migrate]~| WARNING this error has been downgraded to a warning for backwards compatibility
54 //[migrate]~| WARNING this represents potential undefined behavior in your code
57 // This, by analogy to previous case, is *also* not okay.
59 // (But again, AST-borrowck was not smart enogh to know that this
60 // should be an error.)
61 fn boxed_scribbled<'a>(s: Box<Scribble<'a>>) -> &'a mut u32 {
62 &mut *(*s).0 //[nll]~ ERROR borrow may still be in use when destructor runs [E0713]
63 //[migrate]~^ WARNING borrow may still be in use when destructor runs [E0713]
64 //[migrate]~| WARNING this error has been downgraded to a warning for backwards compatibility
65 //[migrate]~| WARNING this represents potential undefined behavior in your code
68 // This, by analogy to previous case, is *also* not okay.
70 // (But again, AST-borrowck was not smart enogh to know that this
71 // should be an error.)
72 fn boxed_boxed_scribbled<'a>(s: Box<Box<Scribble<'a>>>) -> &'a mut u32 {
73 &mut *(**s).0 //[nll]~ ERROR borrow may still be in use when destructor runs [E0713]
74 //[migrate]~^ WARNING borrow may still be in use when destructor runs [E0713]
75 //[migrate]~| WARNING this error has been downgraded to a warning for backwards compatibility
76 //[migrate]~| WARNING this represents potential undefined behavior in your code
80 fn main() { //[migrate]~ ERROR compilation successful
83 let mut long_lived = Scribble(&mut x);
84 *borrowed_scribble(&mut long_lived) += 10;
85 // (Scribble dtor runs here, after `&mut`-borrow above ends)
88 let mut long_lived = Scribble(&mut x);
89 *boxed_borrowed_scribble(Box::new(&mut long_lived)) += 10;
90 // (Scribble dtor runs here, after `&mut`-borrow above ends)
93 let mut long_lived = Scribble(&mut x);
94 *boxed_boxed_borrowed_scribble(Box::new(Box::new(&mut long_lived))) += 10;
95 // (Scribble dtor runs here, after `&mut`-borrow above ends)
97 *scribbled(Scribble(&mut x)) += 10;
98 *boxed_scribbled(Box::new(Scribble(&mut x))) += 10;
99 *boxed_boxed_scribbled(Box::new(Box::new(Scribble(&mut x)))) += 10;