@@ -239,12 +239,23 @@ fn is_ok_to_suggest<'tcx>(cx: &LateContext<'tcx>, lhs: &Expr<'tcx>, call: &CallC
239239///
240240/// This cannot be written `s2.clone_into(&mut s)` because it has conflicting borrows.
241241fn clone_source_borrows_from_dest ( cx : & LateContext < ' _ > , lhs : & Expr < ' _ > , call_span : Span ) -> bool {
242+ /// If this basic block only exists to drop a local as part of an assignment, returns its
243+ /// successor. Otherwise returns the basic block that was passed in.
244+ fn skip_drop_block ( mir : & mir:: Body < ' _ > , bb : mir:: BasicBlock ) -> mir:: BasicBlock {
245+ if let mir:: TerminatorKind :: Drop { target, .. } = mir. basic_blocks [ bb] . terminator ( ) . kind {
246+ target
247+ } else {
248+ bb
249+ }
250+ }
251+
242252 let Some ( mir) = enclosing_mir ( cx. tcx , lhs. hir_id ) else {
243253 return false ;
244254 } ;
245255 let PossibleBorrowerMap { map : borrow_map, .. } = PossibleBorrowerMap :: new ( cx, mir) ;
246256
247- // The operation `dest = src.to_owned()` in MIR is split up across 3 blocks.
257+ // The operation `dest = src.to_owned()` in MIR is split up across 3 blocks *if* the type has `Drop`
258+ // code. For types that don't, the second basic block is simply skipped.
248259 // For the doc example above that would be roughly:
249260 //
250261 // bb0:
@@ -260,26 +271,28 @@ fn clone_source_borrows_from_dest(cx: &LateContext<'_>, lhs: &Expr<'_>, call_spa
260271 let terminator = bb. terminator ( ) ;
261272
262273 // Look for the to_owned/clone call.
263- if terminator. source_info . span == call_span
264- && let mir:: TerminatorKind :: Call {
265- args,
266- target : Some ( drop_bb) ,
267- ..
268- } = & terminator. kind
274+ if terminator. source_info . span != call_span {
275+ continue ;
276+ }
277+
278+ if let mir:: TerminatorKind :: Call { ref args, target : Some ( assign_bb) , .. } = terminator. kind
269279 && let [ source] = & * * args
270280 && let mir:: Operand :: Move ( source) = & source. node
271- // Block 2 only has the `drop()` terminator from to the assignment
272- && let drop_bb = & mir. basic_blocks [ * drop_bb]
273- && let mir:: TerminatorKind :: Drop { target : assign_bb, .. } = drop_bb. terminator ( ) . kind
274- // Block 3 has the final assignment to the original local
275- && let assign_bb = & mir. basic_blocks [ assign_bb]
276- && let [ assignment, ..] = & * assign_bb. statements
281+ && let assign_bb = skip_drop_block ( mir, assign_bb)
282+ // Skip any storage statements as they are just noise
283+ && let Some ( assignment) = mir. basic_blocks [ assign_bb] . statements
284+ . iter ( )
285+ . find ( |stmt| {
286+ !matches ! ( stmt. kind, mir:: StatementKind :: StorageDead ( _) | mir:: StatementKind :: StorageLive ( _) )
287+ } )
277288 && let mir:: StatementKind :: Assign ( box ( borrowed, _) ) = & assignment. kind
278289 && let Some ( borrowers) = borrow_map. get ( & borrowed. local )
279290 && borrowers. contains ( source. local )
280291 {
281292 return true ;
282293 }
294+
295+ return false ;
283296 }
284297 false
285298}
0 commit comments