Skip to content

Commit 7eb29e3

Browse files
authored
Merge pull request #36995 from DougGregor/data-race-checking-flags-5.5
[5.5] [SILGen] Put actor data-race checking behind a flag.
2 parents 61c60e8 + 817a2c0 commit 7eb29e3

File tree

17 files changed

+138
-17
lines changed

17 files changed

+138
-17
lines changed

include/swift/AST/Attr.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,11 @@ CONTEXTUAL_SIMPLE_DECL_ATTR(_unsafeMainActor, UnsafeMainActor,
647647
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIBreakingToRemove,
648648
114)
649649

650+
SIMPLE_DECL_ATTR(_implicitSelfCapture, ImplicitSelfCapture,
651+
OnParam | UserInaccessible |
652+
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIBreakingToRemove,
653+
115)
654+
650655
#undef TYPE_ATTR
651656
#undef DECL_ATTR_ALIAS
652657
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Expr.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,10 +292,14 @@ class alignas(8) Expr {
292292
Kind : 2
293293
);
294294

295-
SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1,
295+
SWIFT_INLINE_BITFIELD(ClosureExpr, AbstractClosureExpr, 1+1,
296296
/// True if closure parameters were synthesized from anonymous closure
297297
/// variables.
298-
HasAnonymousClosureVars : 1
298+
HasAnonymousClosureVars : 1,
299+
300+
/// True if "self" can be captured implicitly without requiring "self."
301+
/// on each member reference.
302+
ImplicitSelfCapture : 1
299303
);
300304

301305
SWIFT_INLINE_BITFIELD_FULL(BindOptionalExpr, Expr, 16,
@@ -3871,6 +3875,7 @@ class ClosureExpr : public AbstractClosureExpr {
38713875
Body(nullptr) {
38723876
setParameterList(params);
38733877
Bits.ClosureExpr.HasAnonymousClosureVars = false;
3878+
Bits.ClosureExpr.ImplicitSelfCapture = false;
38743879
}
38753880

38763881
SourceRange getSourceRange() const;
@@ -3898,7 +3903,17 @@ class ClosureExpr : public AbstractClosureExpr {
38983903
void setHasAnonymousClosureVars() {
38993904
Bits.ClosureExpr.HasAnonymousClosureVars = true;
39003905
}
3901-
3906+
3907+
/// Whether this closure allows "self" to be implicitly captured without
3908+
/// required "self." on each reference.
3909+
bool allowsImplicitSelfCapture() const {
3910+
return Bits.ClosureExpr.ImplicitSelfCapture;
3911+
}
3912+
3913+
void setAllowsImplicitSelfCapture(bool value = true) {
3914+
Bits.ClosureExpr.ImplicitSelfCapture = value;
3915+
}
3916+
39023917
/// Determine whether this closure expression has an
39033918
/// explicitly-specified result type.
39043919
bool hasExplicitResultType() const { return ArrowLoc.isValid(); }

include/swift/AST/SILOptions.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ class SILOptions {
6565
/// It is turned off by default.
6666
bool EnableSpeculativeDevirtualization = false;
6767

68+
/// Controls whether to emit actor data-race checks.
69+
bool EnableActorDataRaceChecks = false;
70+
6871
/// Should we run any SIL performance optimizations
6972
///
7073
/// Useful when you want to enable -O LLVM opts but not -O SIL opts.

include/swift/AST/Types.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3382,6 +3382,7 @@ struct ParameterListInfo {
33823382
SmallBitVector propertyWrappers;
33833383
SmallBitVector unsafeSendable;
33843384
SmallBitVector unsafeMainActor;
3385+
SmallBitVector implicitSelfCapture;
33853386

33863387
public:
33873388
ParameterListInfo() { }
@@ -3410,6 +3411,13 @@ struct ParameterListInfo {
34103411
/// part of the type system.
34113412
bool isUnsafeMainActor(unsigned paramIdx) const;
34123413

3414+
/// Whether the given parameter is a closure that should allow capture of
3415+
/// 'self' to be implicit, without requiring "self.".
3416+
bool isImplicitSelfCapture(unsigned paramIdx) const;
3417+
3418+
/// Whether there is any contextual information set on this parameter list.
3419+
bool anyContextualInfo() const;
3420+
34133421
/// Retrieve the number of non-defaulted parameters.
34143422
unsigned numNonDefaultedParameters() const {
34153423
return defaultArguments.count();

include/swift/Option/Options.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,16 @@ def warn_swift3_objc_inference_minimal :
607607
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
608608
HelpText<"Warn about deprecated @objc inference in Swift 3 based on direct uses of the Objective-C entrypoint">;
609609

610+
def enable_actor_data_race_checks :
611+
Flag<["-"], "enable-actor-data-race-checks">,
612+
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
613+
HelpText<"Emit runtime checks for actor data races">;
614+
615+
def disable_actor_data_race_checks :
616+
Flag<["-"], "disable-actor-data-race-checks">,
617+
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
618+
HelpText<"Disable runtime checks for actor data races">;
619+
610620
def warn_implicit_overrides :
611621
Flag<["-"], "warn-implicit-overrides">,
612622
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,

lib/AST/ASTDumper.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2546,6 +2546,8 @@ class PrintExpr : public ExprVisitor<PrintExpr> {
25462546
printClosure(E, "closure_expr");
25472547
if (E->hasSingleExpressionBody())
25482548
PrintWithColorRAII(OS, ClosureModifierColor) << " single-expression";
2549+
if (E->allowsImplicitSelfCapture())
2550+
PrintWithColorRAII(OS, ClosureModifierColor) << " implicit-self";
25492551

25502552
if (E->getParameters()) {
25512553
OS << '\n';

lib/AST/Type.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,7 @@ ParameterListInfo::ParameterListInfo(
970970
propertyWrappers.resize(params.size());
971971
unsafeSendable.resize(params.size());
972972
unsafeMainActor.resize(params.size());
973+
implicitSelfCapture.resize(params.size());
973974

974975
// No parameter owner means no parameter list means no default arguments
975976
// - hand back the zeroed bitvector.
@@ -1029,6 +1030,10 @@ ParameterListInfo::ParameterListInfo(
10291030
if (param->getAttrs().hasAttribute<UnsafeMainActorAttr>()) {
10301031
unsafeMainActor.set(i);
10311032
}
1033+
1034+
if (param->getAttrs().hasAttribute<ImplicitSelfCaptureAttr>()) {
1035+
implicitSelfCapture.set(i);
1036+
}
10321037
}
10331038
}
10341039

@@ -1059,6 +1064,17 @@ bool ParameterListInfo::isUnsafeMainActor(unsigned paramIdx) const {
10591064
: false;
10601065
}
10611066

1067+
bool ParameterListInfo::isImplicitSelfCapture(unsigned paramIdx) const {
1068+
return paramIdx < implicitSelfCapture.size()
1069+
? implicitSelfCapture[paramIdx]
1070+
: false;
1071+
}
1072+
1073+
bool ParameterListInfo::anyContextualInfo() const {
1074+
return unsafeSendable.any() || unsafeMainActor.any() ||
1075+
implicitSelfCapture.any();
1076+
}
1077+
10621078
/// Turn a param list into a symbolic and printable representation that does not
10631079
/// include the types, something like (_:, b:, c:)
10641080
std::string swift::getParamListAsString(ArrayRef<AnyFunctionType::Param> params) {

lib/Driver/ToolChains.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
217217
inputArgs.AddLastArg(arguments,
218218
options::OPT_warn_swift3_objc_inference_minimal,
219219
options::OPT_warn_swift3_objc_inference_complete);
220+
inputArgs.AddLastArg(arguments,
221+
options::OPT_enable_actor_data_race_checks,
222+
options::OPT_disable_actor_data_race_checks);
220223
inputArgs.AddLastArg(arguments, options::OPT_warn_concurrency);
221224
inputArgs.AddLastArg(arguments, options::OPT_warn_implicit_overrides);
222225
inputArgs.AddLastArg(arguments, options::OPT_typo_correction_limit);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,6 +1222,9 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
12221222
Opts.EnableOSSAModules |= Args.hasArg(OPT_enable_ossa_modules);
12231223
Opts.EnableOSSAOptimizations &= !Args.hasArg(OPT_disable_ossa_opts);
12241224
Opts.EnableSpeculativeDevirtualization |= Args.hasArg(OPT_enable_spec_devirt);
1225+
Opts.EnableActorDataRaceChecks |= Args.hasFlag(
1226+
OPT_enable_actor_data_race_checks,
1227+
OPT_disable_actor_data_race_checks, /*default=*/false);
12251228
Opts.DisableSILPerfOptimizations |= Args.hasArg(OPT_disable_sil_perf_optzns);
12261229
Opts.CrossModuleOptimization |= Args.hasArg(OPT_CrossModuleOptimization);
12271230
Opts.VerifyAll |= Args.hasArg(OPT_sil_verify_all);

lib/SILGen/SILGenProlog.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,10 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
492492

493493
// Initialize ExpectedExecutor if the function is an actor-isolated
494494
// function or closure.
495+
bool wantDataRaceChecks = getOptions().EnableActorDataRaceChecks &&
496+
!F.isAsync() &&
497+
!isInActorDestructor(FunctionDC);
498+
495499
if (auto *funcDecl =
496500
dyn_cast_or_null<AbstractFunctionDecl>(FunctionDC->getAsDecl())) {
497501
auto actorIsolation = getActorIsolation(funcDecl);
@@ -508,7 +512,7 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
508512
// are prone to dynamic data races in code that does not enforce Sendable
509513
// completely.
510514
if (F.isAsync() ||
511-
(funcDecl->isLocalCapture() && !isInActorDestructor(funcDecl))) {
515+
(wantDataRaceChecks && funcDecl->isLocalCapture())) {
512516
auto loc = RegularLocation::getAutoGeneratedLocation(F.getLocation());
513517
ManagedValue selfArg = ManagedValue::forUnmanaged(F.getSelfArgument());
514518
ExpectedExecutor = emitLoadActorExecutor(loc, selfArg);
@@ -517,14 +521,17 @@ void SILGenFunction::emitProlog(CaptureInfo captureInfo,
517521
}
518522

519523
case ActorIsolation::GlobalActor:
520-
if (F.isAsync() || !isInActorDestructor(funcDecl)) {
524+
if (F.isAsync() || wantDataRaceChecks) {
521525
ExpectedExecutor =
522526
emitLoadGlobalActorExecutor(actorIsolation.getGlobalActor());
523527
}
524528
break;
525529
}
526530
} else if (auto *closureExpr = dyn_cast<AbstractClosureExpr>(FunctionDC)) {
527-
bool wantExecutor = F.isAsync() || !isInActorDestructor(closureExpr);
531+
bool wantExecutor = F.isAsync() ||
532+
(wantDataRaceChecks &&
533+
!(isa<ClosureExpr>(closureExpr) &&
534+
cast<ClosureExpr>(closureExpr)->isUnsafeMainActor()));
528535
auto actorIsolation = closureExpr->getActorIsolation();
529536
switch (actorIsolation.getKind()) {
530537
case ClosureActorIsolation::Independent:

lib/Sema/CSApply.cpp

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5711,16 +5711,18 @@ static bool hasCurriedSelf(ConstraintSystem &cs, ConcreteDeclRef callee,
57115711
}
57125712

57135713
/// Apply the contextually Sendable flag to the given expression,
5714-
static void applyUnsafeConcurrent(
5715-
Expr *expr, bool sendable, bool forMainActor) {
5714+
static void applyContextualClosureFlags(
5715+
Expr *expr, bool sendable, bool forMainActor, bool implicitSelfCapture) {
57165716
if (auto closure = dyn_cast<ClosureExpr>(expr)) {
57175717
closure->setUnsafeConcurrent(sendable, forMainActor);
5718+
closure->setAllowsImplicitSelfCapture(implicitSelfCapture);
57185719
return;
57195720
}
57205721

57215722
if (auto captureList = dyn_cast<CaptureListExpr>(expr)) {
5722-
applyUnsafeConcurrent(
5723-
captureList->getClosureBody(), sendable, forMainActor);
5723+
applyContextualClosureFlags(
5724+
captureList->getClosureBody(), sendable, forMainActor,
5725+
implicitSelfCapture);
57245726
}
57255727
}
57265728

@@ -5808,7 +5810,8 @@ Expr *ExprRewriter::coerceCallArguments(
58085810

58095811
// Quickly test if any further fix-ups for the argument types are necessary.
58105812
if (AnyFunctionType::equalParams(args, params) &&
5811-
!shouldInjectWrappedValuePlaceholder)
5813+
!shouldInjectWrappedValuePlaceholder &&
5814+
!paramInfo.anyContextualInfo())
58125815
return arg;
58135816

58145817
// Apply labels to arguments.
@@ -5979,9 +5982,10 @@ Expr *ExprRewriter::coerceCallArguments(
59795982
bool isUnsafeSendable = paramInfo.isUnsafeSendable(paramIdx);
59805983
bool isMainActor = paramInfo.isUnsafeMainActor(paramIdx) ||
59815984
(isUnsafeSendable && apply && isMainDispatchQueue(apply->getFn()));
5982-
applyUnsafeConcurrent(
5985+
bool isImplicitSelfCapture = paramInfo.isImplicitSelfCapture(paramIdx);
5986+
applyContextualClosureFlags(
59835987
arg, isUnsafeSendable && contextUsesConcurrencyFeatures(dc),
5984-
isMainActor);
5988+
isMainActor, isImplicitSelfCapture);
59855989

59865990
// If the types exactly match, this is easy.
59875991
auto paramType = param.getOldType();

lib/Sema/MiscDiagnostics.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,13 @@ static void diagnoseImplicitSelfUseInClosure(const Expr *E,
15701570
return false;
15711571
}
15721572

1573+
// If the closure was used in a context where it's explicitly stated
1574+
// that it does not need "self." qualification, don't require it.
1575+
if (auto closure = dyn_cast<ClosureExpr>(CE)) {
1576+
if (closure->allowsImplicitSelfCapture())
1577+
return false;
1578+
}
1579+
15731580
return true;
15741581
}
15751582

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
137137
IGNORED_ATTR(AtReasync)
138138
IGNORED_ATTR(UnsafeSendable)
139139
IGNORED_ATTR(UnsafeMainActor)
140+
IGNORED_ATTR(ImplicitSelfCapture)
140141
#undef IGNORED_ATTR
141142

142143
void visitAlignmentAttr(AlignmentAttr *attr) {

lib/Sema/TypeCheckDeclOverride.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1546,7 +1546,7 @@ namespace {
15461546
UNINTERESTING_ATTR(Nonisolated)
15471547
UNINTERESTING_ATTR(UnsafeSendable)
15481548
UNINTERESTING_ATTR(UnsafeMainActor)
1549-
1549+
UNINTERESTING_ATTR(ImplicitSelfCapture)
15501550
#undef UNINTERESTING_ATTR
15511551

15521552
void visitAvailableAttr(AvailableAttr *attr) {

test/Concurrency/Runtime/data_race_detection.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-concurrency %import-libdispatch -parse-as-library) > %t.log 2>&1
1+
// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-concurrency -enable-actor-data-race-checks %import-libdispatch -parse-as-library) > %t.log 2>&1
22
// RUN: %FileCheck %s < %t.log
33

44
// REQUIRES: executable_test

test/SILGen/check_executor.swift

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %target-swift-frontend -emit-silgen %s -module-name test -swift-version 5 -enable-experimental-concurrency | %FileCheck --enable-var-scope %s --check-prefix=CHECK-RAW
2-
// RUN: %target-swift-frontend -emit-silgen %s -module-name test -swift-version 5 -enable-experimental-concurrency > %t.sil
1+
// RUN: %target-swift-frontend -emit-silgen %s -module-name test -swift-version 5 -enable-experimental-concurrency -enable-actor-data-race-checks | %FileCheck --enable-var-scope %s --check-prefix=CHECK-RAW
2+
// RUN: %target-swift-frontend -emit-silgen %s -module-name test -swift-version 5 -enable-experimental-concurrency -enable-actor-data-race-checks > %t.sil
33
// RUN: %target-sil-opt -enable-sil-verify-all %t.sil -lower-hop-to-actor -enable-experimental-concurrency | %FileCheck --enable-var-scope %s --check-prefix=CHECK-CANONICAL
44
// REQUIRES: concurrency
55

@@ -15,6 +15,8 @@ import _Concurrency
1515

1616
func takeClosure(_ fn: @escaping () -> Int) { }
1717

18+
func takeUnsafeMainActorClosure(@_unsafeMainActor _ fn: @escaping () -> Int) { }
19+
1820
public actor MyActor {
1921
var counter = 0
2022

@@ -36,4 +38,15 @@ public actor MyActor {
3638
deinit {
3739
takeClosure { self.counter }
3840
}
41+
42+
// CHECK-RAW-LABEL: sil private [ossa] @$s4test7MyActorC0A10UnsafeMainyyFSiycfU_
43+
// CHECK-RAW-NOT: _checkExpectedExecutor
44+
// CHECK-RAW: onMainActor
45+
// CHECK-RAW: return
46+
public func testUnsafeMain() {
47+
takeUnsafeMainActorClosure {
48+
onMainActor()
49+
return 5
50+
}
51+
}
3952
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %target-typecheck-verify-swift
2+
3+
func takeFn(@_implicitSelfCapture fn: @escaping () -> Int) { }
4+
func takeEscapingFn(fn: @escaping () -> Int) { }
5+
6+
class C {
7+
var property: Int = 0
8+
9+
func method() { }
10+
11+
func testMethod() {
12+
takeFn { // no errors
13+
method()
14+
return property
15+
}
16+
17+
takeEscapingFn { // expected-note 2 {{capture 'self' explicitly to enable implicit 'self' in this closure}}
18+
method() // expected-error{{call to method 'method' in closure requires explicit use of 'self' to make capture semantics explicit}}
19+
// expected-note@-1{{reference 'self.' explicitly}}
20+
return property // expected-error{{reference to property 'property' in closure requires explicit use of 'self' to make capture semantics explicit}}
21+
// expected-note@-1{{reference 'self.' explicitly}}
22+
}
23+
}
24+
}

0 commit comments

Comments
 (0)