@@ -388,6 +388,11 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
388
388
case SILInstructionKind::ExplicitCopyAddrInst:
389
389
case SILInstructionKind::ExplicitCopyValueInst:
390
390
break ; // Explicitly acknowledged copies are OK.
391
+ case SILInstructionKind::CopyAddrInst: {
392
+ if (!cast<CopyAddrInst>(inst)->isTakeOfSrc ())
393
+ shouldDiagnose = true ; // If it isn't a [take], it's a copy.
394
+ break ;
395
+ }
391
396
case SILInstructionKind::LoadInst: {
392
397
// FIXME: we don't have an `explicit_load` and transparent functions can
393
398
// end up bringing in a `load [copy]`. A better approach is needed to
@@ -429,38 +434,53 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
429
434
<< " \n has unexpected copying instruction: " << *inst);
430
435
431
436
// Try to come up with a useful diagnostic.
437
+
438
+ // First, identify what is being copied.
439
+ SILValue copied;
432
440
if (auto svi = dyn_cast<SingleValueInstruction>(inst)) {
433
- if (auto name = VariableNameInferrer::inferName (svi)) {
434
- // Simplistic check for whether this is a closure capture.
435
- for (auto user : svi->getUsers ()) {
436
- if (isa<PartialApplyInst>(user)) {
437
- LLVM_DEBUG (llvm::dbgs () << " captured by " << *user);
438
- diagnose (loc, diag::manualownership_copy_captured, *name);
439
- return false ;
440
- }
441
- }
441
+ copied = svi;
442
+ } else if (auto cai = dyn_cast<CopyAddrInst>(inst)) {
443
+ copied = cai->getSrc ();
444
+ }
442
445
443
- // There's no hope of borrowing access if there's a consuming use.
444
- for (auto op : svi->getUses ()) {
445
- auto useKind = op->getOperandOwnership ();
446
-
447
- // Only some DestroyingConsume's, like 'store', are interesting.
448
- if (useKind == OperandOwnership::ForwardingConsume
449
- || isa<StoreInst>(op->getUser ())) {
450
- LLVM_DEBUG (llvm::dbgs () << " demanded by " << *(op->getUser ()));
451
- diagnose (loc, diag::manualownership_copy_demanded, *name);
452
- return false ;
453
- }
454
- }
446
+ // Find a name for that copied thing.
447
+ std::optional<Identifier> name;
448
+ if (copied)
449
+ name = VariableNameInferrer::inferName (copied);
450
+
451
+ if (!name) {
452
+ // Emit a rudimentary diagnostic.
453
+ diagnose (loc, diag::manualownership_copy);
454
+ return false ;
455
+ }
455
456
456
- diagnose (loc, diag::manualownership_copy_happened, *name);
457
+ // Try to tailor the diagnostic based on usages.
458
+
459
+ // Simplistic check for whether this is a closure capture.
460
+ for (auto user : copied->getUsers ()) {
461
+ if (isa<PartialApplyInst>(user)) {
462
+ LLVM_DEBUG (llvm::dbgs () << " captured by " << *user);
463
+ diagnose (loc, diag::manualownership_copy_captured, name->get ());
457
464
return false ;
458
465
}
459
466
}
460
467
461
- // Back-up diagnostic, when all-else fails.
462
- diagnose (loc, diag::manualownership_copy);
463
- return false ; // Don't bail-out early; diagnose more issues in the func.
468
+ // There's no hope of borrowing access if there's a consuming use.
469
+ for (auto op : copied->getUses ()) {
470
+ auto useKind = op->getOperandOwnership ();
471
+
472
+ // Only some DestroyingConsume's, like 'store', are interesting.
473
+ if (useKind == OperandOwnership::ForwardingConsume
474
+ || isa<StoreInst>(op->getUser ())) {
475
+ LLVM_DEBUG (llvm::dbgs () << " demanded by " << *(op->getUser ()));
476
+ diagnose (loc, diag::manualownership_copy_demanded, *name);
477
+ return false ;
478
+ }
479
+ }
480
+
481
+ // Catch-all diagnostic for when we at least have the name.
482
+ diagnose (loc, diag::manualownership_copy_happened, *name);
483
+ return false ;
464
484
}
465
485
}
466
486
return false ;
0 commit comments