Skip to content

Commit e943c91

Browse files
committed
ManualOwnership: improve diagnostics for address types
We can find the name of the source of a copy_addr to give less confusing messages.
1 parent 32263bb commit e943c91

File tree

2 files changed

+50
-35
lines changed

2 files changed

+50
-35
lines changed

lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -434,38 +434,53 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
434434
<< "\n has unexpected copying instruction: " << *inst);
435435

436436
// Try to come up with a useful diagnostic.
437+
438+
// First, identify what is being copied.
439+
SILValue copied;
437440
if (auto svi = dyn_cast<SingleValueInstruction>(inst)) {
438-
if (auto name = VariableNameInferrer::inferName(svi)) {
439-
// Simplistic check for whether this is a closure capture.
440-
for (auto user : svi->getUsers()) {
441-
if (isa<PartialApplyInst>(user)) {
442-
LLVM_DEBUG(llvm::dbgs() << "captured by "<< *user);
443-
diagnose(loc, diag::manualownership_copy_captured, *name);
444-
return false;
445-
}
446-
}
441+
copied = svi;
442+
} else if (auto cai = dyn_cast<CopyAddrInst>(inst)) {
443+
copied = cai->getSrc();
444+
}
447445

448-
// There's no hope of borrowing access if there's a consuming use.
449-
for (auto op : svi->getUses()) {
450-
auto useKind = op->getOperandOwnership();
451-
452-
// Only some DestroyingConsume's, like 'store', are interesting.
453-
if (useKind == OperandOwnership::ForwardingConsume
454-
|| isa<StoreInst>(op->getUser())) {
455-
LLVM_DEBUG(llvm::dbgs() << "demanded by "<< *(op->getUser()));
456-
diagnose(loc, diag::manualownership_copy_demanded, *name);
457-
return false;
458-
}
459-
}
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+
}
456+
457+
// Try to tailor the diagnostic based on usages.
460458

461-
diagnose(loc, diag::manualownership_copy_happened, *name);
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);
462464
return false;
463465
}
464466
}
465467

466-
// Back-up diagnostic, when all-else fails.
467-
diagnose(loc, diag::manualownership_copy);
468-
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;
469484
}
470485
}
471486
return false;

test/SIL/manual_ownership.swift

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ func nested_closures_fixed(_ t: Triangle) -> () -> (() -> Triangle) {
387387

388388
@_manualOwnership
389389
func return_generic<T>(_ t: T) -> T {
390-
return t // expected-error {{explicit 'copy' required here}}
390+
return t // expected-error {{accessing 't' produces a copy}}
391391
}
392392
@_manualOwnership
393393
func return_generic_fixed<T>(_ t: T) -> T {
@@ -396,9 +396,9 @@ func return_generic_fixed<T>(_ t: T) -> T {
396396

397397
@_manualOwnership
398398
func reassign_with_lets<T>(_ t: T) -> T {
399-
let x = t // expected-error {{explicit 'copy' required here}}
400-
let y = x // expected-error {{explicit 'copy' required here}}
401-
let z = y // expected-error {{explicit 'copy' required here}}
399+
let x = t // expected-error {{accessing 't' produces a copy}}
400+
let y = x // expected-error {{accessing 'x' produces a copy}}
401+
let z = y // expected-error {{accessing 'y' produces a copy}}
402402
return copy z
403403
}
404404

@@ -413,9 +413,9 @@ func reassign_with_lets_fixed<T>(_ t: T) -> T {
413413

414414
@_manualOwnership
415415
func copy_generic<T>(_ t: T) {
416-
consume_generic(t) // expected-error {{explicit 'copy' required here}}
416+
consume_generic(t) // expected-error {{accessing 't' produces a copy}}
417417
borrow_generic(t)
418-
consume_generic(t) // expected-error {{explicit 'copy' required here}}
418+
consume_generic(t) // expected-error {{accessing 't' produces a copy}}
419419
}
420420

421421
@_manualOwnership
@@ -429,10 +429,10 @@ func copy_generic_fixed<T>(_ t: T) {
429429
func benchCaptureProp<S : Sequence>(
430430
_ s: S, _ f: (S.Element, S.Element) -> S.Element) -> S.Element {
431431

432-
var it = s.makeIterator() // expected-error {{explicit 'copy' required here}}
432+
var it = s.makeIterator() // expected-error {{accessing 's' produces a copy}}
433433
let initial = it.next()!
434434
return
435-
IteratorSequence(it) // expected-error {{explicit 'copy' required here}}
435+
IteratorSequence(it) // expected-error {{accessing 'it' produces a copy}}
436436
.reduce(initial, f)
437437
}
438438
@_manualOwnership
@@ -464,8 +464,8 @@ struct CollectionOf32BitLittleEndianIntegers<BaseCollection: Collection> where B
464464
@_manualOwnership
465465
init(_ baseCollection: BaseCollection) {
466466
precondition(baseCollection.count % 4 == 0)
467-
self.baseCollection = baseCollection // expected-error {{explicit 'copy' required here}}
468-
} // expected-error {{explicit 'copy' required here}}
467+
self.baseCollection = baseCollection // expected-error {{accessing 'baseCollection' produces a copy}}
468+
} // expected-error {{accessing 'self' produces a copy of it}}
469469

470470
// FIXME: the above initializer shouldn't have any diagnostics
471471
}

0 commit comments

Comments
 (0)