11#![ feature( const_mut_refs) ]
22#![ feature( const_fn) ]
3+ #![ feature( const_transmute) ]
34#![ feature( raw_ref_op) ]
5+ #![ feature( const_raw_ptr_deref) ]
6+
47const NULL : * mut i32 = std:: ptr:: null_mut ( ) ;
58const A : * const i32 = & 4 ;
69
@@ -9,6 +12,25 @@ const A: *const i32 = &4;
912// as that would be an enormous footgun in oli-obk's opinion.
1013const B : * mut i32 = & mut 4 ; //~ ERROR mutable references are not allowed
1114
15+ // Ok, no actual mutable allocation exists
16+ const B2 : Option < & mut i32 > = None ;
17+
18+ // Not ok, can't prove that no mutable allocation ends up in final value
19+ const B3 : Option < & mut i32 > = Some ( & mut 42 ) ; //~ ERROR temporary value dropped while borrowed
20+
21+ const fn helper ( ) -> Option < & ' static mut i32 > { unsafe {
22+ // Undefined behaviour, who doesn't love tests like this.
23+ // This code never gets executed, because the static checks fail before that.
24+ Some ( & mut * ( 42 as * mut i32 ) )
25+ } }
26+ // Check that we do not look into function bodies.
27+ // We treat all functions as not returning a mutable reference, because there is no way to
28+ // do that without causing the borrow checker to complain (see the B5/helper2 test below).
29+ const B4 : Option < & mut i32 > = helper ( ) ;
30+
31+ const fn helper2 ( x : & mut i32 ) -> Option < & mut i32 > { Some ( x) }
32+ const B5 : Option < & mut i32 > = helper2 ( & mut 42 ) ; //~ ERROR temporary value dropped while borrowed
33+
1234// Ok, because no references to mutable data exist here, since the `{}` moves
1335// its value and then takes a reference to that.
1436const C : * const i32 = & {
@@ -17,7 +39,30 @@ const C: *const i32 = &{
1739 x
1840} ;
1941
42+ use std:: cell:: UnsafeCell ;
43+ struct NotAMutex < T > ( UnsafeCell < T > ) ;
44+
45+ unsafe impl < T > Sync for NotAMutex < T > { }
46+
47+ const FOO : NotAMutex < & mut i32 > = NotAMutex ( UnsafeCell :: new ( & mut 42 ) ) ;
48+ //~^ ERROR temporary value dropped while borrowed
49+
50+ static FOO2 : NotAMutex < & mut i32 > = NotAMutex ( UnsafeCell :: new ( & mut 42 ) ) ;
51+ //~^ ERROR temporary value dropped while borrowed
52+
53+ static mut FOO3 : NotAMutex < & mut i32 > = NotAMutex ( UnsafeCell :: new ( & mut 42 ) ) ;
54+ //~^ ERROR temporary value dropped while borrowed
55+
56+ // `BAR` works, because `&42` promotes immediately instead of relying on
57+ // the enclosing scope rule.
58+ const BAR : NotAMutex < & i32 > = NotAMutex ( UnsafeCell :: new ( & 42 ) ) ;
59+
2060fn main ( ) {
2161 println ! ( "{}" , unsafe { * A } ) ;
2262 unsafe { * B = 4 } // Bad news
63+
64+ unsafe {
65+ * * FOO . 0 . get ( ) = 99 ;
66+ assert_eq ! ( * * FOO . 0 . get( ) , 99 ) ;
67+ }
2368}
0 commit comments