Diagnose captured of non-sendable metatypes crossing isolation boundaries

Keep track of all of the type parameters and archetypes that are captured
by a local function or closure. Use that information to diagnose cases
where a non-Sendable metatype crosses an isolation boundary.
This commit is contained in:
Doug Gregor
2025-02-13 14:36:52 -08:00
parent b1e9673a47
commit ed6dccf12c
10 changed files with 210 additions and 84 deletions

View File

@@ -17,6 +17,7 @@
#include "swift/Basic/LLVM.h"
#include "swift/Basic/OptionSet.h"
#include "swift/Basic/SourceLoc.h"
#include "swift/AST/Type.h"
#include "swift/AST/TypeAlignments.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/PointerIntPair.h"
@@ -129,6 +130,18 @@ public:
unsigned getFlags() const { return Value.getInt(); }
};
/// Describes a type that has been captured by a closure or local function.
class CapturedType {
Type type;
SourceLoc loc;
public:
CapturedType(Type type, SourceLoc loc) : type(type), loc(loc) { }
Type getType() const { return type; }
SourceLoc getLoc() const { return loc; }
};
} // end swift namespace
namespace swift {
@@ -140,26 +153,32 @@ class CaptureInfo {
class CaptureInfoStorage final
: public llvm::TrailingObjects<CaptureInfoStorage,
CapturedValue,
GenericEnvironment *> {
GenericEnvironment *,
CapturedType> {
DynamicSelfType *DynamicSelf;
OpaqueValueExpr *OpaqueValue;
unsigned NumCapturedValues;
unsigned NumGenericEnvironments;
unsigned NumCapturedTypes;
public:
explicit CaptureInfoStorage(DynamicSelfType *dynamicSelf,
OpaqueValueExpr *opaqueValue,
unsigned numCapturedValues,
unsigned numGenericEnvironments)
unsigned numGenericEnvironments,
unsigned numCapturedTypes)
: DynamicSelf(dynamicSelf), OpaqueValue(opaqueValue),
NumCapturedValues(numCapturedValues),
NumGenericEnvironments(numGenericEnvironments) { }
NumGenericEnvironments(numGenericEnvironments),
NumCapturedTypes(numCapturedTypes) { }
ArrayRef<CapturedValue> getCaptures() const;
ArrayRef<GenericEnvironment *> getGenericEnvironments() const;
ArrayRef<CapturedType> getCapturedTypes() const;
DynamicSelfType *getDynamicSelfType() const {
return DynamicSelf;
}
@@ -171,6 +190,14 @@ class CaptureInfo {
unsigned numTrailingObjects(OverloadToken<CapturedValue>) const {
return NumCapturedValues;
}
unsigned numTrailingObjects(OverloadToken<GenericEnvironment *>) const {
return NumGenericEnvironments;
}
unsigned numTrailingObjects(OverloadToken<CapturedType>) const {
return NumCapturedTypes;
}
};
enum class Flags : unsigned {
@@ -187,7 +214,8 @@ public:
ArrayRef<CapturedValue> captures,
DynamicSelfType *dynamicSelf, OpaqueValueExpr *opaqueValue,
bool genericParamCaptures,
ArrayRef<GenericEnvironment *> genericEnv=ArrayRef<GenericEnvironment*>());
ArrayRef<GenericEnvironment *> genericEnv=ArrayRef<GenericEnvironment*>(),
ArrayRef<CapturedType> capturedTypes = ArrayRef<CapturedType>());
/// A CaptureInfo representing no captures at all.
static CaptureInfo empty();
@@ -196,11 +224,7 @@ public:
return StorageAndFlags.getPointer();
}
bool isTrivial() const {
assert(hasBeenComputed());
return getCaptures().empty() && !hasGenericParamCaptures() &&
!hasDynamicSelfCapture() && !hasOpaqueValueCapture();
}
bool isTrivial() const;
/// Returns all captured values and opaque expressions.
ArrayRef<CapturedValue> getCaptures() const {
@@ -214,6 +238,12 @@ public:
return StorageAndFlags.getPointer()->getGenericEnvironments();
}
/// Returns all captured values and opaque expressions.
ArrayRef<CapturedType> getCapturedTypes() const {
assert(hasBeenComputed());
return StorageAndFlags.getPointer()->getCapturedTypes();
}
/// \returns true if the function captures the primary generic environment
/// from its innermost declaration context.
bool hasGenericParamCaptures() const {

View File

@@ -5607,6 +5607,10 @@ ERROR(non_sendable_isolated_capture,none,
"capture of %1 with non-sendable type %0 in an isolated "
"%select{local function|closure}2",
(Type, DeclName, bool))
ERROR(non_sendable_metatype_capture,none,
"capture of non-sendable type %0 in an isolated "
"%select{local function|closure}1",
(Type, bool))
ERROR(self_capture_deinit_task,none,
"capture of 'self' in a closure that outlives deinit",
())