Skip to content

Commit a77d119

Browse files
authored
Merge pull request #71261 from xedin/introduce-thunks-for-runtime-check-func-refs
[Sema/SILGen] DynamicActorIsolation: Implement dynamic actor isolation checks for unsafe APIs
2 parents b12370a + 53b2d86 commit a77d119

30 files changed

+494
-72
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2734,6 +2734,10 @@ class ValueDecl : public Decl {
27342734
}
27352735

27362736
public:
2737+
/// Find the import that makes the given declaration available.
2738+
llvm::Optional<AttributedImport<ImportedModule>>
2739+
findImport(const DeclContext *fromDC);
2740+
27372741
/// Return true if this protocol member is a protocol requirement.
27382742
///
27392743
/// Asserts if this is not a member of a protocol.

include/swift/AST/DiagnosticsSema.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5642,7 +5642,7 @@ ERROR(preconcurrency_not_inheritance_clause,none,
56425642
ERROR(preconcurrency_not_existential,none,
56435643
"'preconcurrency' attribute cannot apply to non-protocol type %0", (Type))
56445644
ERROR(preconcurrency_attr_disabled,none,
5645-
"attribute requires '-enable-experimental-feature PreconcurrencyConformances'", ())
5645+
"attribute requires '-enable-experimental-feature DynamicActorIsolation'", ())
56465646

56475647
ERROR(redundant_any_in_existential,none,
56485648
"redundant 'any' in type %0",

include/swift/AST/Expr.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3519,6 +3519,19 @@ class BridgeToObjCExpr : public ImplicitConversionExpr {
35193519
}
35203520
};
35213521

3522+
/// ActorIsolationErasureExpr - A special kind of function conversion that
3523+
/// drops actor isolation.
3524+
class ActorIsolationErasureExpr : public ImplicitConversionExpr {
3525+
public:
3526+
ActorIsolationErasureExpr(Expr *subExpr, Type type)
3527+
: ImplicitConversionExpr(ExprKind::ActorIsolationErasure, subExpr, type) {
3528+
}
3529+
3530+
static bool classof(const Expr *E) {
3531+
return E->getKind() == ExprKind::ActorIsolationErasure;
3532+
}
3533+
};
3534+
35223535
/// UnresolvedSpecializeExpr - Represents an explicit specialization using
35233536
/// a type parameter list (e.g. "Vector<Int>") that has not been resolved.
35243537
class UnresolvedSpecializeExpr final : public Expr,

include/swift/AST/ExprNodes.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ ABSTRACT_EXPR(ImplicitConversion, Expr)
189189
EXPR(DifferentiableFunctionExtractOriginal, ImplicitConversionExpr)
190190
EXPR(LinearFunctionExtractOriginal, ImplicitConversionExpr)
191191
EXPR(LinearToDifferentiableFunction, ImplicitConversionExpr)
192-
EXPR_RANGE(ImplicitConversion, Load, LinearToDifferentiableFunction)
192+
EXPR(ActorIsolationErasure, ImplicitConversionExpr)
193+
EXPR_RANGE(ImplicitConversion, Load, ActorIsolationErasure)
193194
ABSTRACT_EXPR(ExplicitCast, Expr)
194195
ABSTRACT_EXPR(CheckedCast, ExplicitCastExpr)
195196
EXPR(ForcedCheckedCast, CheckedCastExpr)

include/swift/AST/FileUnit.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/RawComment.h"
1818
#include "swift/Basic/BasicSourceInfo.h"
1919
#include "swift/Basic/Debug.h"
20+
#include "swift/Basic/Version.h"
2021

2122
#include "llvm/ADT/PointerIntPair.h"
2223

@@ -417,6 +418,10 @@ class LoadedFile : public FileUnit {
417418
assert(classof(this) && "invalid kind");
418419
}
419420
public:
421+
/// Returns the language version that was used to compile the contents of this
422+
/// file. An empty `Version` is returned if the information is not available.
423+
virtual version::Version getLanguageVersionBuiltWith() const = 0;
424+
420425
/// Returns an arbitrary string representing the storage backing this file.
421426
///
422427
/// This is usually a filesystem path.

include/swift/AST/Module.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,6 +1147,10 @@ class ModuleDecl
11471147

11481148
SourceRange getSourceRange() const { return SourceRange(); }
11491149

1150+
/// Returns the language version that was used to compile this module.
1151+
/// An empty `Version` is returned if the information is not available.
1152+
version::Version getLanguageVersionBuiltWith() const;
1153+
11501154
static bool classof(const DeclContext *DC) {
11511155
if (auto D = DC->getAsDecl())
11521156
return classof(D);

include/swift/Basic/Features.def

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,10 @@ EXPERIMENTAL_FEATURE(GroupActorErrors, true)
268268
// Allow for the 'transferring' keyword to be applied to arguments and results.
269269
EXPERIMENTAL_FEATURE(TransferringArgsAndResults, true)
270270

271-
// Enable `@preconcurrency` attribute on protocol conformances.
272-
EXPERIMENTAL_FEATURE(PreconcurrencyConformances, false)
271+
// Enable `@preconcurrency` attribute on protocol conformances and runtime checks
272+
// of actor isolation in @obj thunks and arguments of APIs that haven't yet adopted
273+
// strict concurrency checking.
274+
EXPERIMENTAL_FEATURE(DynamicActorIsolation, false)
273275

274276
// Allow for `switch` of noncopyable values to be borrowing or consuming.
275277
EXPERIMENTAL_FEATURE(BorrowingSwitch, true)

include/swift/ClangImporter/ClangModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#define SWIFT_CLANGIMPORTER_CLANGMODULE_H
1818

1919
#include "swift/AST/FileUnit.h"
20+
#include "swift/Basic/Version.h"
2021
#include "swift/ClangImporter/ClangImporter.h"
2122
#include "clang/AST/ExternalASTSource.h"
2223
#include "clang/Basic/Module.h"
@@ -109,6 +110,10 @@ class ClangModuleUnit final : public LoadedFile {
109110
llvm_unreachable("no private decls in Clang modules");
110111
}
111112

113+
virtual version::Version getLanguageVersionBuiltWith() const override {
114+
return version::Version();
115+
}
116+
112117
virtual StringRef getFilename() const override;
113118

114119
virtual StringRef getLoadedFilename() const override;

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ class SerializedASTFile final : public LoadedFile {
400400

401401
/// Returns the language version that was used to compile the contents of this
402402
/// file.
403-
const version::Version &getLanguageVersionBuiltWith() const;
403+
virtual version::Version getLanguageVersionBuiltWith() const override;
404404

405405
virtual bool hadLoadError() const override;
406406

lib/AST/ASTDumper.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2695,6 +2695,13 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
26952695
printFoot();
26962696
}
26972697

2698+
void visitActorIsolationErasureExpr(ActorIsolationErasureExpr *E,
2699+
StringRef label) {
2700+
printCommon(E, "actor_isolation_erasure_expr", label);
2701+
printRec(E->getSubExpr());
2702+
printFoot();
2703+
}
2704+
26982705
void visitInOutExpr(InOutExpr *E, StringRef label) {
26992706
printCommon(E, "inout_expr", label);
27002707
printRec(E->getSubExpr());

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3880,7 +3880,7 @@ static bool usesFeatureTransferringArgsAndResults(Decl *decl) {
38803880
return false;
38813881
}
38823882

3883-
static bool usesFeaturePreconcurrencyConformances(Decl *decl) {
3883+
static bool usesFeatureDynamicActorIsolation(Decl *decl) {
38843884
auto usesPreconcurrencyConformance = [&](const InheritedTypes &inherited) {
38853885
return llvm::any_of(
38863886
inherited.getEntries(),
@@ -5930,6 +5930,9 @@ void PrintAST::visitLinearFunctionExtractOriginalExpr(swift::LinearFunctionExtra
59305930
void PrintAST::visitLinearToDifferentiableFunctionExpr(swift::LinearToDifferentiableFunctionExpr *expr) {
59315931
}
59325932

5933+
void PrintAST::visitActorIsolationErasureExpr(ActorIsolationErasureExpr *expr) {
5934+
}
5935+
59335936
void PrintAST::visitPropertyWrapperValuePlaceholderExpr(swift::PropertyWrapperValuePlaceholderExpr *expr) {
59345937
}
59355938

lib/AST/Decl.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/AST/Expr.h"
3131
#include "swift/AST/GenericEnvironment.h"
3232
#include "swift/AST/GenericSignature.h"
33+
#include "swift/AST/ImportCache.h"
3334
#include "swift/AST/Initializer.h"
3435
#include "swift/AST/InverseMarking.h"
3536
#include "swift/AST/LazyResolver.h"
@@ -3790,6 +3791,37 @@ ValueDecl::getSatisfiedProtocolRequirements(bool Sorted) const {
37903791
return NTD->getSatisfiedProtocolRequirementsForMember(this, Sorted);
37913792
}
37923793

3794+
llvm::Optional<AttributedImport<ImportedModule>>
3795+
ValueDecl::findImport(const DeclContext *fromDC) {
3796+
// If the type is from the current module, there's no import.
3797+
auto module = getModuleContext();
3798+
if (module == fromDC->getParentModule())
3799+
return llvm::None;
3800+
3801+
auto fromSourceFile = fromDC->getParentSourceFile();
3802+
if (!fromSourceFile)
3803+
return llvm::None;
3804+
3805+
// Look to see if the owning module was directly imported.
3806+
for (const auto &import : fromSourceFile->getImports()) {
3807+
if (import.module.importedModule == module)
3808+
return import;
3809+
}
3810+
3811+
// Now look for transitive imports.
3812+
auto &importCache = getASTContext().getImportCache();
3813+
for (const auto &import : fromSourceFile->getImports()) {
3814+
auto &importSet = importCache.getImportSet(import.module.importedModule);
3815+
for (const auto &transitive : importSet.getTransitiveImports()) {
3816+
if (transitive.importedModule == module) {
3817+
return import;
3818+
}
3819+
}
3820+
}
3821+
3822+
return llvm::None;
3823+
}
3824+
37933825
bool ValueDecl::isProtocolRequirement() const {
37943826
assert(isa<ProtocolDecl>(getDeclContext()));
37953827

lib/AST/Expr.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const {
456456
PASS_THROUGH_REFERENCE(ConditionalBridgeFromObjC, getSubExpr);
457457
PASS_THROUGH_REFERENCE(UnderlyingToOpaque, getSubExpr);
458458
PASS_THROUGH_REFERENCE(Unreachable, getSubExpr);
459+
PASS_THROUGH_REFERENCE(ActorIsolationErasure, getSubExpr);
459460
NO_REFERENCE(Coerce);
460461
NO_REFERENCE(ForcedCheckedCast);
461462
NO_REFERENCE(ConditionalCheckedCast);
@@ -822,6 +823,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const {
822823
case ExprKind::BridgeToObjC:
823824
case ExprKind::UnderlyingToOpaque:
824825
case ExprKind::Unreachable:
826+
case ExprKind::ActorIsolationErasure:
825827
// Implicit conversion nodes have no syntax of their own; defer to the
826828
// subexpression.
827829
return cast<ImplicitConversionExpr>(this)->getSubExpr()
@@ -1029,6 +1031,7 @@ bool Expr::isValidParentOfTypeExpr(Expr *typeExpr) const {
10291031
case ExprKind::TypeJoin:
10301032
case ExprKind::MacroExpansion:
10311033
case ExprKind::CurrentContextIsolation:
1034+
case ExprKind::ActorIsolationErasure:
10321035
return false;
10331036
}
10341037

@@ -1562,6 +1565,10 @@ static ValueDecl *getCalledValue(Expr *E, bool skipFunctionConversions) {
15621565
if (skipFunctionConversions) {
15631566
if (auto fnConv = dyn_cast<FunctionConversionExpr>(E))
15641567
return getCalledValue(fnConv->getSubExpr(), skipFunctionConversions);
1568+
1569+
if (auto *actorErasure = dyn_cast<ActorIsolationErasureExpr>(E))
1570+
return getCalledValue(actorErasure->getSubExpr(),
1571+
skipFunctionConversions);
15651572
}
15661573

15671574
Expr *E2 = E->getValueProvidingExpr();

lib/AST/Module.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3935,3 +3935,17 @@ bool IsNonUserModuleRequest::evaluate(Evaluator &evaluator, ModuleDecl *mod) con
39353935
return (!runtimePath.empty() && pathStartsWith(runtimePath, modulePath)) ||
39363936
(!sdkPath.empty() && pathStartsWith(sdkPath, modulePath));
39373937
}
3938+
3939+
version::Version ModuleDecl::getLanguageVersionBuiltWith() const {
3940+
for (auto *F : getFiles()) {
3941+
auto *LD = dyn_cast<LoadedFile>(F);
3942+
if (!LD)
3943+
continue;
3944+
3945+
auto version = LD->getLanguageVersionBuiltWith();
3946+
if (!version.empty())
3947+
return version;
3948+
}
3949+
3950+
return version::Version();
3951+
}

lib/ClangImporter/DWARFImporter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ class DWARFModuleUnit final : public LoadedFile {
8282
llvm_unreachable("no private decls in Clang modules");
8383
}
8484

85+
virtual version::Version getLanguageVersionBuiltWith() const override {
86+
return version::Version();
87+
}
88+
8589
virtual StringRef getFilename() const override { return ""; }
8690

8791
virtual const clang::Module *getUnderlyingClangModule() const override {

lib/SILGen/SILGenBridging.cpp

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,11 +1594,18 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
15941594
Scope scope(Cleanups, CleanupLocation(loc));
15951595

15961596
bool emitExecutorPrecondition =
1597-
getASTContext().LangOpts.hasFeature(Feature::PreconcurrencyConformances);
1597+
getASTContext().LangOpts.hasFeature(Feature::DynamicActorIsolation);
15981598

15991599
llvm::Optional<ActorIsolation> isolation;
1600-
if ((F.isAsync() || emitExecutorPrecondition) && thunk.hasDecl()) {
1601-
isolation = getActorIsolation(thunk.getDecl());
1600+
if (F.isAsync()) {
1601+
if (thunk.hasDecl())
1602+
isolation = getActorIsolation(thunk.getDecl());
1603+
} else if (emitExecutorPrecondition) {
1604+
if (thunk.hasDecl()) {
1605+
isolation = getActorIsolation(thunk.getDecl());
1606+
} else if (auto globalActor = nativeInfo.FormalType->getGlobalActor()) {
1607+
isolation = ActorIsolation::forGlobalActor(globalActor);
1608+
}
16021609
}
16031610

16041611
// A hop/check is only needed in the thunk if it is global-actor isolated.

lib/SILGen/SILGenExpr.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,8 @@ namespace {
484484
}
485485
RValue visitFunctionConversionExpr(FunctionConversionExpr *E,
486486
SGFContext C);
487+
RValue visitActorIsolationErasureExpr(ActorIsolationErasureExpr *E,
488+
SGFContext C);
487489
RValue visitCovariantFunctionConversionExpr(
488490
CovariantFunctionConversionExpr *E,
489491
SGFContext C);
@@ -2115,6 +2117,21 @@ RValue RValueEmitter::visitCovariantReturnConversionExpr(
21152117
return RValue(SGF, e, result);
21162118
}
21172119

2120+
RValue RValueEmitter::visitActorIsolationErasureExpr(ActorIsolationErasureExpr *E,
2121+
SGFContext C) {
2122+
auto loc = SILLocation(E).asAutoGenerated();
2123+
auto funcRef = SGF.emitRValueAsSingleValue(E->getSubExpr());
2124+
2125+
auto isolatedType =
2126+
cast<AnyFunctionType>(E->getSubExpr()->getType()->getCanonicalType());
2127+
auto nonIsolatedType =
2128+
cast<AnyFunctionType>(E->getType()->getCanonicalType());
2129+
2130+
return RValue(SGF, E,
2131+
SGF.emitActorIsolationErasureThunk(loc, funcRef, isolatedType,
2132+
nonIsolatedType));
2133+
}
2134+
21182135
RValue RValueEmitter::visitErasureExpr(ErasureExpr *E, SGFContext C) {
21192136
if (auto result = tryEmitAsBridgingConversion(SGF, E, false, C)) {
21202137
return RValue(SGF, E, *result);

lib/SILGen/SILGenFunction.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,13 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
908908
/// new task.
909909
SILFunction *emitNativeAsyncToForeignThunk(SILDeclRef thunk);
910910

911+
/// Generates a thunk that contains a runtime precondition that
912+
/// the given function is called on the expected executor.
913+
ManagedValue emitActorIsolationErasureThunk(SILLocation loc,
914+
ManagedValue func,
915+
CanAnyFunctionType isolatedType,
916+
CanAnyFunctionType nonIsolatedType);
917+
911918
/// Generate a nullary function that returns the given value.
912919
/// If \p emitProfilerIncrement is set, emit a profiler increment for
913920
/// \p value.

0 commit comments

Comments
 (0)