Skip to content

Commit ed6dccf

Browse files
committed
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.
1 parent b1e9673 commit ed6dccf

File tree

10 files changed

+210
-84
lines changed

10 files changed

+210
-84
lines changed

include/swift/AST/CaptureInfo.h

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/Basic/LLVM.h"
1818
#include "swift/Basic/OptionSet.h"
1919
#include "swift/Basic/SourceLoc.h"
20+
#include "swift/AST/Type.h"
2021
#include "swift/AST/TypeAlignments.h"
2122
#include "llvm/ADT/ArrayRef.h"
2223
#include "llvm/ADT/PointerIntPair.h"
@@ -129,6 +130,18 @@ class CapturedValue {
129130
unsigned getFlags() const { return Value.getInt(); }
130131
};
131132

133+
/// Describes a type that has been captured by a closure or local function.
134+
class CapturedType {
135+
Type type;
136+
SourceLoc loc;
137+
138+
public:
139+
CapturedType(Type type, SourceLoc loc) : type(type), loc(loc) { }
140+
141+
Type getType() const { return type; }
142+
SourceLoc getLoc() const { return loc; }
143+
};
144+
132145
} // end swift namespace
133146

134147
namespace swift {
@@ -140,26 +153,32 @@ class CaptureInfo {
140153
class CaptureInfoStorage final
141154
: public llvm::TrailingObjects<CaptureInfoStorage,
142155
CapturedValue,
143-
GenericEnvironment *> {
156+
GenericEnvironment *,
157+
CapturedType> {
144158

145159
DynamicSelfType *DynamicSelf;
146160
OpaqueValueExpr *OpaqueValue;
147161
unsigned NumCapturedValues;
148162
unsigned NumGenericEnvironments;
163+
unsigned NumCapturedTypes;
149164

150165
public:
151166
explicit CaptureInfoStorage(DynamicSelfType *dynamicSelf,
152167
OpaqueValueExpr *opaqueValue,
153168
unsigned numCapturedValues,
154-
unsigned numGenericEnvironments)
169+
unsigned numGenericEnvironments,
170+
unsigned numCapturedTypes)
155171
: DynamicSelf(dynamicSelf), OpaqueValue(opaqueValue),
156172
NumCapturedValues(numCapturedValues),
157-
NumGenericEnvironments(numGenericEnvironments) { }
173+
NumGenericEnvironments(numGenericEnvironments),
174+
NumCapturedTypes(numCapturedTypes) { }
158175

159176
ArrayRef<CapturedValue> getCaptures() const;
160177

161178
ArrayRef<GenericEnvironment *> getGenericEnvironments() const;
162179

180+
ArrayRef<CapturedType> getCapturedTypes() const;
181+
163182
DynamicSelfType *getDynamicSelfType() const {
164183
return DynamicSelf;
165184
}
@@ -171,6 +190,14 @@ class CaptureInfo {
171190
unsigned numTrailingObjects(OverloadToken<CapturedValue>) const {
172191
return NumCapturedValues;
173192
}
193+
194+
unsigned numTrailingObjects(OverloadToken<GenericEnvironment *>) const {
195+
return NumGenericEnvironments;
196+
}
197+
198+
unsigned numTrailingObjects(OverloadToken<CapturedType>) const {
199+
return NumCapturedTypes;
200+
}
174201
};
175202

176203
enum class Flags : unsigned {
@@ -187,7 +214,8 @@ class CaptureInfo {
187214
ArrayRef<CapturedValue> captures,
188215
DynamicSelfType *dynamicSelf, OpaqueValueExpr *opaqueValue,
189216
bool genericParamCaptures,
190-
ArrayRef<GenericEnvironment *> genericEnv=ArrayRef<GenericEnvironment*>());
217+
ArrayRef<GenericEnvironment *> genericEnv=ArrayRef<GenericEnvironment*>(),
218+
ArrayRef<CapturedType> capturedTypes = ArrayRef<CapturedType>());
191219

192220
/// A CaptureInfo representing no captures at all.
193221
static CaptureInfo empty();
@@ -196,11 +224,7 @@ class CaptureInfo {
196224
return StorageAndFlags.getPointer();
197225
}
198226

199-
bool isTrivial() const {
200-
assert(hasBeenComputed());
201-
return getCaptures().empty() && !hasGenericParamCaptures() &&
202-
!hasDynamicSelfCapture() && !hasOpaqueValueCapture();
203-
}
227+
bool isTrivial() const;
204228

205229
/// Returns all captured values and opaque expressions.
206230
ArrayRef<CapturedValue> getCaptures() const {
@@ -214,6 +238,12 @@ class CaptureInfo {
214238
return StorageAndFlags.getPointer()->getGenericEnvironments();
215239
}
216240

241+
/// Returns all captured values and opaque expressions.
242+
ArrayRef<CapturedType> getCapturedTypes() const {
243+
assert(hasBeenComputed());
244+
return StorageAndFlags.getPointer()->getCapturedTypes();
245+
}
246+
217247
/// \returns true if the function captures the primary generic environment
218248
/// from its innermost declaration context.
219249
bool hasGenericParamCaptures() const {

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5607,6 +5607,10 @@ ERROR(non_sendable_isolated_capture,none,
56075607
"capture of %1 with non-sendable type %0 in an isolated "
56085608
"%select{local function|closure}2",
56095609
(Type, DeclName, bool))
5610+
ERROR(non_sendable_metatype_capture,none,
5611+
"capture of non-sendable type %0 in an isolated "
5612+
"%select{local function|closure}1",
5613+
(Type, bool))
56105614
ERROR(self_capture_deinit_task,none,
56115615
"capture of 'self' in a closure that outlives deinit",
56125616
())

lib/AST/CaptureInfo.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ CaptureInfo::CaptureInfoStorage::getGenericEnvironments() const {
5454
return llvm::ArrayRef(this->getTrailingObjects<GenericEnvironment *>(), NumGenericEnvironments);
5555
}
5656

57+
ArrayRef<CapturedType>
58+
CaptureInfo::CaptureInfoStorage::getCapturedTypes() const {
59+
return llvm::ArrayRef(this->getTrailingObjects<CapturedType>(), NumCapturedTypes);
60+
}
61+
5762
//===----------------------------------------------------------------------===//
5863
// MARK: CaptureInfo
5964
//===----------------------------------------------------------------------===//
@@ -62,7 +67,8 @@ CaptureInfo::CaptureInfo(ASTContext &ctx, ArrayRef<CapturedValue> captures,
6267
DynamicSelfType *dynamicSelf,
6368
OpaqueValueExpr *opaqueValue,
6469
bool genericParamCaptures,
65-
ArrayRef<GenericEnvironment *> genericEnv) {
70+
ArrayRef<GenericEnvironment *> genericEnv,
71+
ArrayRef<CapturedType> capturedTypes) {
6672
static_assert(IsTriviallyDestructible<CapturedValue>::value,
6773
"Capture info is alloc'd on the ASTContext and not destroyed");
6874
static_assert(IsTriviallyDestructible<CaptureInfo::CaptureInfoStorage>::value,
@@ -79,37 +85,49 @@ CaptureInfo::CaptureInfo(ASTContext &ctx, ArrayRef<CapturedValue> captures,
7985
if (genericParamCaptures)
8086
flags |= Flags::HasGenericParamCaptures;
8187

82-
if (captures.empty() && genericEnv.empty() && !dynamicSelf && !opaqueValue) {
88+
if (captures.empty() && genericEnv.empty() && !dynamicSelf && !opaqueValue &&
89+
capturedTypes.empty()) {
8390
*this = CaptureInfo::empty();
8491
StorageAndFlags.setInt(flags);
8592
return;
8693
}
8794

8895
size_t storageToAlloc =
8996
CaptureInfoStorage::totalSizeToAlloc<CapturedValue,
90-
GenericEnvironment *>(captures.size(),
91-
genericEnv.size());
97+
GenericEnvironment *,
98+
CapturedType>(captures.size(),
99+
genericEnv.size(),
100+
capturedTypes.size());
92101
void *storageBuf = ctx.Allocate(storageToAlloc, alignof(CaptureInfoStorage));
93102
auto *storage = new (storageBuf) CaptureInfoStorage(dynamicSelf,
94103
opaqueValue,
95104
captures.size(),
96-
genericEnv.size());
105+
genericEnv.size(),
106+
capturedTypes.size());
97107
StorageAndFlags.setPointerAndInt(storage, flags);
98108
std::uninitialized_copy(captures.begin(), captures.end(),
99109
storage->getTrailingObjects<CapturedValue>());
100110
std::uninitialized_copy(genericEnv.begin(), genericEnv.end(),
101111
storage->getTrailingObjects<GenericEnvironment *>());
112+
std::uninitialized_copy(capturedTypes.begin(), capturedTypes.end(),
113+
storage->getTrailingObjects<CapturedType>());
102114
}
103115

104116
CaptureInfo CaptureInfo::empty() {
105117
static const CaptureInfoStorage empty{/*dynamicSelf*/nullptr,
106118
/*opaqueValue*/nullptr,
107-
0, 0};
119+
0, 0, 0};
108120
CaptureInfo result;
109121
result.StorageAndFlags.setPointer(&empty);
110122
return result;
111123
}
112124

125+
bool CaptureInfo::isTrivial() const {
126+
assert(hasBeenComputed());
127+
return getCaptures().empty() && !hasGenericParamCaptures() &&
128+
!hasDynamicSelfCapture() && !hasOpaqueValueCapture();
129+
}
130+
113131
VarDecl *CaptureInfo::getIsolatedParamCapture() const {
114132
for (const auto &capture : getCaptures()) {
115133
// NOTE: isLocalCapture() returns false if we have dynamic self metadata
@@ -178,6 +196,12 @@ void CaptureInfo::print(raw_ostream &OS) const {
178196
OS << genericEnv->getOpenedElementShapeClass();
179197
},
180198
[&] { OS << ","; });
199+
200+
interleave(getCapturedTypes(),
201+
[&](CapturedType type) {
202+
OS << " type=" << type.getType().getString();
203+
},
204+
[&] { OS << ","; });
181205
OS << ')';
182206
}
183207

lib/SIL/IR/TypeLowering.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4425,6 +4425,10 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
44254425
// Captured pack element environments.
44264426
llvm::SetVector<GenericEnvironment *> genericEnv;
44274427

4428+
// Captured types.
4429+
SmallVector<CapturedType, 4> capturedTypes;
4430+
llvm::SmallDenseSet<CanType, 4> alreadyCapturedTypes;
4431+
44284432
bool capturesGenericParams = false;
44294433
DynamicSelfType *capturesDynamicSelf = nullptr;
44304434
OpaqueValueExpr *capturesOpaqueValue = nullptr;
@@ -4620,6 +4624,13 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
46204624
// Collect non-function captures.
46214625
recordCapture(capture);
46224626
}
4627+
4628+
for (const auto &capturedType : captureInfo.getCapturedTypes()) {
4629+
if (alreadyCapturedTypes.insert(capturedType.getType()->getCanonicalType())
4630+
.second) {
4631+
capturedTypes.push_back(capturedType);
4632+
}
4633+
}
46234634
};
46244635

46254636
collectFunctionCaptures = [&](AnyFunctionRef curFn) {
@@ -4697,7 +4708,8 @@ TypeConverter::getLoweredLocalCaptures(SILDeclRef fn) {
46974708
// Cache the result.
46984709
CaptureInfo info(Context, resultingCaptures,
46994710
capturesDynamicSelf, capturesOpaqueValue,
4700-
capturesGenericParams, genericEnv.getArrayRef());
4711+
capturesGenericParams, genericEnv.getArrayRef(),
4712+
capturedTypes);
47014713
auto inserted = LoweredCaptures.insert({fn, info});
47024714
assert(inserted.second && "already in map?!");
47034715
(void)inserted;

lib/Sema/TypeCheckCaptures.cpp

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@ class FindCapturedVars : public ASTWalker {
5454
/// can go here too.
5555
llvm::SetVector<GenericEnvironment *> CapturedEnvironments;
5656

57+
/// The captured types.
58+
SmallVector<CapturedType, 4> CapturedTypes;
59+
llvm::SmallDenseMap<CanType, unsigned, 4> CapturedTypeEntryNumber;
60+
5761
SourceLoc GenericParamCaptureLoc;
5862
SourceLoc DynamicSelfCaptureLoc;
5963
DynamicSelfType *DynamicSelf = nullptr;
@@ -83,7 +87,8 @@ class FindCapturedVars : public ASTWalker {
8387

8488
return CaptureInfo(Context, Captures, dynamicSelfToRecord,
8589
OpaqueValue, HasGenericParamCaptures,
86-
CapturedEnvironments.getArrayRef());
90+
CapturedEnvironments.getArrayRef(),
91+
CapturedTypes);
8792
}
8893

8994
bool hasGenericParamCaptures() const {
@@ -156,6 +161,22 @@ class FindCapturedVars : public ASTWalker {
156161
}));
157162
}
158163

164+
// Note that we're using a generic type.
165+
auto recordUseOfGenericType = [&](Type type) {
166+
if (!HasGenericParamCaptures) {
167+
GenericParamCaptureLoc = loc;
168+
HasGenericParamCaptures = true;
169+
}
170+
171+
auto [insertionPos, inserted] = CapturedTypeEntryNumber.insert(
172+
{type->getCanonicalType(), CapturedTypes.size()});
173+
if (inserted) {
174+
CapturedTypes.push_back(CapturedType(type, loc));
175+
} else if (CapturedTypes[insertionPos->second].getLoc().isInvalid()) {
176+
CapturedTypes[insertionPos->second] = CapturedType(type, loc);
177+
}
178+
};
179+
159180
// Similar to dynamic 'Self', IRGen doesn't really need type metadata
160181
// for class-bound archetypes in nearly as many cases as with opaque
161182
// archetypes.
@@ -174,23 +195,18 @@ class FindCapturedVars : public ASTWalker {
174195
CapturedEnvironments.insert(env);
175196
}
176197

177-
if ((t->is<PrimaryArchetypeType>() ||
178-
t->is<PackArchetypeType>() ||
179-
t->is<GenericTypeParamType>()) &&
180-
!HasGenericParamCaptures) {
181-
GenericParamCaptureLoc = loc;
182-
HasGenericParamCaptures = true;
198+
if (t->is<PrimaryArchetypeType>() ||
199+
t->is<PackArchetypeType>() ||
200+
t->is<GenericTypeParamType>()) {
201+
recordUseOfGenericType(t);
183202
}
184203
}));
185204
}
186205

187206
if (auto *gft = type->getAs<GenericFunctionType>()) {
188207
TypeCaptureWalker walker(ObjC, [&](Type t) {
189-
if (t->is<GenericTypeParamType>() &&
190-
!HasGenericParamCaptures) {
191-
GenericParamCaptureLoc = loc;
192-
HasGenericParamCaptures = true;
193-
}
208+
if (t->is<GenericTypeParamType>())
209+
recordUseOfGenericType(t);
194210
});
195211

196212
for (const auto &param : gft->getParams())

0 commit comments

Comments
 (0)