@@ -22,13 +22,14 @@ pub type MaybeMutBorrowedLocals<'mir, 'tcx> = MaybeBorrowedLocals<MutBorrow<'mir
2222/// function call or inline assembly.
2323pub struct MaybeBorrowedLocals < K = AnyBorrow > {
2424 kind : K ,
25+ ignore_borrow_on_drop : bool ,
2526}
2627
2728impl MaybeBorrowedLocals {
2829 /// A dataflow analysis that records whether a pointer or reference exists that may alias the
2930 /// given local.
3031 pub fn all_borrows ( ) -> Self {
31- MaybeBorrowedLocals { kind : AnyBorrow }
32+ MaybeBorrowedLocals { kind : AnyBorrow , ignore_borrow_on_drop : false }
3233 }
3334}
3435
@@ -43,13 +44,37 @@ impl MaybeMutBorrowedLocals<'mir, 'tcx> {
4344 body : & ' mir mir:: Body < ' tcx > ,
4445 param_env : ParamEnv < ' tcx > ,
4546 ) -> Self {
46- MaybeBorrowedLocals { kind : MutBorrow { body, tcx, param_env } }
47+ MaybeBorrowedLocals {
48+ kind : MutBorrow { body, tcx, param_env } ,
49+ ignore_borrow_on_drop : false ,
50+ }
4751 }
4852}
4953
5054impl < K > MaybeBorrowedLocals < K > {
55+ /// During dataflow analysis, ignore the borrow that may occur when a place is dropped.
56+ ///
57+ /// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a
58+ /// parameter. In the general case, a drop impl could launder that reference into the
59+ /// surrounding environment through a raw pointer, thus creating a valid `*mut` pointing to the
60+ /// dropped local. We are not yet willing to declare this particular case UB, so we must treat
61+ /// all dropped locals as mutably borrowed for now. See discussion on [#61069].
62+ ///
63+ /// In some contexts, we know that this borrow will never occur. For example, during
64+ /// const-eval, custom drop glue cannot be run. Code that calls this should document the
65+ /// assumptions that justify `Drop` terminators in this way.
66+ ///
67+ /// [#61069]: https://github.com/rust-lang/rust/pull/61069
68+ pub fn unsound_ignore_borrow_on_drop ( self ) -> Self {
69+ MaybeBorrowedLocals { ignore_borrow_on_drop : true , ..self }
70+ }
71+
5172 fn transfer_function < ' a , T > ( & ' a self , trans : & ' a mut T ) -> TransferFunction < ' a , T , K > {
52- TransferFunction { kind : & self . kind , trans }
73+ TransferFunction {
74+ kind : & self . kind ,
75+ trans,
76+ ignore_borrow_on_drop : self . ignore_borrow_on_drop ,
77+ }
5378 }
5479}
5580
@@ -112,6 +137,7 @@ impl<K> BottomValue for MaybeBorrowedLocals<K> {
112137struct TransferFunction < ' a , T , K > {
113138 trans : & ' a mut T ,
114139 kind : & ' a K ,
140+ ignore_borrow_on_drop : bool ,
115141}
116142
117143impl < T , K > Visitor < ' tcx > for TransferFunction < ' a , T , K >
@@ -162,17 +188,12 @@ where
162188 self . super_terminator ( terminator, location) ;
163189
164190 match terminator. kind {
165- // Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self`
166- // as a parameter. Hypothetically, a drop impl could launder that reference into the
167- // surrounding environment through a raw pointer, thus creating a valid `*mut` pointing
168- // to the dropped local. We are not yet willing to declare this particular case UB, so
169- // we must treat all dropped locals as mutably borrowed for now. See discussion on
170- // [#61069].
171- //
172- // [#61069]: https://github.com/rust-lang/rust/pull/61069
173191 mir:: TerminatorKind :: Drop { location : dropped_place, .. }
174192 | mir:: TerminatorKind :: DropAndReplace { location : dropped_place, .. } => {
175- self . trans . gen ( dropped_place. local ) ;
193+ // See documentation for `unsound_ignore_borrow_on_drop` for an explanation.
194+ if !self . ignore_borrow_on_drop {
195+ self . trans . gen ( dropped_place. local ) ;
196+ }
176197 }
177198
178199 TerminatorKind :: Abort
0 commit comments