Skip to content

Commit 6b858b4

Browse files
committed
ManualOwnership: introduce 'DynamicExclusivity'
We can add warnings about dynamic exclusivity checks that may happen on an access, with explainers about why they happen for safety.
1 parent 95a6719 commit 6b858b4

File tree

6 files changed

+61
-6
lines changed

6 files changed

+61
-6
lines changed

include/swift/AST/DiagnosticGroups.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ GROUP(ConformanceIsolation, "conformance-isolation")
4949
GROUP(ForeignReferenceType, "foreign-reference-type")
5050
GROUP(DeprecatedDeclaration, "deprecated-declaration")
5151
GROUP(DynamicCallable, "dynamic-callable-requirements")
52+
GROUP(DynamicExclusivity, "dynamic-exclusivity")
5253
GROUP(EmbeddedRestrictions, "embedded-restrictions")
5354
GROUP(ErrorInFutureSwiftVersion, "error-in-future-swift-version")
5455
GROUP(ExclusivityViolation, "exclusivity-violation")

include/swift/AST/DiagnosticsSIL.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,8 @@ ERROR(wrong_linkage_for_serialized_function,none,
433433
"function has wrong linkage to be called from %0", (StringRef))
434434
NOTE(performance_called_from,none,
435435
"called from here", ())
436+
437+
// ManualOwnership diagnostics
436438
GROUPED_WARNING(manualownership_copy,SemanticCopies,none,
437439
"implicit 'copy' happens here; please report this vague diagnostic as a bug", ())
438440
GROUPED_WARNING(manualownership_copy_happened,SemanticCopies,none,
@@ -441,6 +443,10 @@ GROUPED_WARNING(manualownership_copy_demanded,SemanticCopies,none,
441443
"independent copy of %0 is required here; write 'copy' to acknowledge or 'consume' to elide", (Identifier))
442444
GROUPED_WARNING(manualownership_copy_captured,SemanticCopies,none,
443445
"closure capture of '%0' requires independent copy of it; write [%0 = copy %0] in the closure's capture list to acknowledge", (StringRef))
446+
GROUPED_WARNING(manualownership_exclusivity,DynamicExclusivity,none,
447+
"exclusive access here will be checked at runtime", ())
448+
GROUPED_WARNING(manualownership_exclusivity_named,DynamicExclusivity,none,
449+
"accessing %0 here may incur runtime exclusivity check%1", (Identifier, StringRef))
444450

445451
// 'transparent' diagnostics
446452
ERROR(circular_transparent,none,

lib/SILOptimizer/Mandatory/PerformanceDiagnostics.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -489,6 +489,49 @@ bool PerformanceDiagnostics::visitInst(SILInstruction *inst,
489489
return false;
490490
}
491491
}
492+
if (impact & RuntimeEffect::ExclusivityChecking) {
493+
switch (inst->getKind()) {
494+
case SILInstructionKind::BeginUnpairedAccessInst:
495+
case SILInstructionKind::EndUnpairedAccessInst:
496+
// These instructions are quite unusual; they seem to only ever created
497+
// explicitly by calling functions from the Builtin module, see:
498+
// - emitBuiltinPerformInstantaneousReadAccess
499+
// - emitBuiltinEndUnpairedAccess
500+
break;
501+
case SILInstructionKind::EndAccessInst:
502+
break; // We'll already diagnose the begin access.
503+
case SILInstructionKind::BeginAccessInst: {
504+
auto bai = cast<BeginAccessInst>(inst);
505+
auto info = VariableNameInferrer::inferNameAndRoot(bai->getSource());
506+
507+
if (!info) {
508+
LLVM_DEBUG(llvm::dbgs() << "exclusivity (no name?): " << *inst);
509+
diagnose(loc, diag::manualownership_exclusivity);
510+
return false;
511+
}
512+
Identifier name = info->first;
513+
SILValue root = info->second;
514+
StringRef advice = "";
515+
516+
// Try to classify the root to give advice.
517+
if (isa<GlobalAddrInst>(root)) {
518+
advice = ", because it involves a global variable";
519+
} else if (root->getType().isAnyClassReferenceType()) {
520+
advice = ", because it's a member of a reference type";
521+
}
522+
523+
LLVM_DEBUG(llvm::dbgs() << "exclusivity: " << *inst);
524+
LLVM_DEBUG(llvm::dbgs() << "with root: " << root);
525+
526+
diagnose(loc, diag::manualownership_exclusivity_named, name, advice);
527+
break;
528+
}
529+
default:
530+
LLVM_DEBUG(llvm::dbgs() << "UNKNOWN EXCLUSIVITY INST: " << *inst);
531+
diagnose(loc, diag::manualownership_exclusivity);
532+
return false;
533+
}
534+
}
492535
return false;
493536
}
494537

lib/SILOptimizer/Utils/VariableNameUtils.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,7 @@ SILValue VariableNameInferrer::findDebugInfoProvidingValueHelper(
651651
isa<LoadBorrowInst>(searchValue) || isa<BeginAccessInst>(searchValue) ||
652652
isa<MarkUnresolvedNonCopyableValueInst>(searchValue) ||
653653
isa<ProjectBoxInst>(searchValue) || isa<CopyValueInst>(searchValue) ||
654+
isa<ExplicitCopyValueInst>(searchValue) ||
654655
isa<ConvertFunctionInst>(searchValue) ||
655656
isa<MarkUninitializedInst>(searchValue) ||
656657
isa<MarkDependenceInst>(searchValue) ||

test/SIL/manual_ownership.swift

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// RUN: %target-swift-frontend %s -emit-sil -verify \
22
// RUN: -Werror SemanticCopies \
3+
// RUN: -Werror DynamicExclusivity \
34
// RUN: -enable-experimental-feature ManualOwnership
45

56
// REQUIRES: swift_feature_ManualOwnership
@@ -225,19 +226,19 @@ func reassignments_1_fixed_2() {
225226

226227
@_manualOwnership
227228
public func basic_loop_trivial_values(_ t: Triangle, _ xs: [Triangle]) {
228-
var p: Pair = t.a
229+
var p: Pair = t.a // expected-error {{accessing 't.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
229230
for x in xs { // expected-error {{independent copy of 'xs' is required}}
230-
p = p.midpoint(x.a)
231+
p = p.midpoint(x.a) // expected-error {{accessing 'x.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
231232
}
232-
t.a = p
233+
t.a = p // expected-error {{accessing 't.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
233234
}
234235
@_manualOwnership
235236
public func basic_loop_trivial_values_fixed(_ t: Triangle, _ xs: [Triangle]) {
236-
var p: Pair = t.a
237+
var p: Pair = t.a // expected-error {{accessing 't.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
237238
for x in copy xs {
238-
p = p.midpoint(x.a)
239+
p = p.midpoint(x.a) // expected-error {{accessing 'x.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
239240
}
240-
t.a = p
241+
t.a = p // expected-error {{accessing 't.a' here may incur runtime exclusivity check, because it's a member of a reference type}}
241242
}
242243

243244
// FIXME: the only reason for so many copies below is because
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Dynamic Exclusivity (Experimental Diagnostics)
2+
3+
TODO explain

0 commit comments

Comments
 (0)