Skip to content

Commit abcc134

Browse files
authored
Merge pull request #81542 from gottesmm/rdar150209093_rdar151394209
[concurrency] Fix a few issues around not emitted correct protocol witness and vtable thunks for nonisolated(nonsending)
2 parents dfc9647 + ef23f97 commit abcc134

17 files changed

+363
-118
lines changed

include/swift/SIL/TypeLowering.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,6 +1389,14 @@ CanSILFunctionType getNativeSILFunctionType(
13891389
std::optional<SubstitutionMap> reqtSubs = std::nullopt,
13901390
ProtocolConformanceRef witnessMethodConformance = ProtocolConformanceRef());
13911391

1392+
/// origConstant is the parent decl ref in the case of class methods and the
1393+
/// witness method decl ref if we are working with a protocol witness. Pass in
1394+
/// None otherwise.
1395+
std::optional<ActorIsolation>
1396+
getSILFunctionTypeActorIsolation(CanAnyFunctionType substFnInterfaceType,
1397+
std::optional<SILDeclRef> origConstant,
1398+
std::optional<SILDeclRef> constant);
1399+
13921400
/// The thunk kinds used in the differentiation transform.
13931401
enum class DifferentiationThunkKind {
13941402
/// A reabstraction thunk.

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 64 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2386,6 +2386,68 @@ static void destructureYieldsForCoroutine(TypeConverter &TC,
23862386
}
23872387
}
23882388

2389+
std::optional<ActorIsolation>
2390+
swift::getSILFunctionTypeActorIsolation(CanAnyFunctionType substFnInterfaceType,
2391+
std::optional<SILDeclRef> origConstant,
2392+
std::optional<SILDeclRef> constant) {
2393+
// If we have origConstant then we are creating a protocol method thunk. In
2394+
// such a case, we want to use the origConstant's actor isolation.
2395+
if (origConstant && constant &&
2396+
*origConstant != *constant) {
2397+
if (auto *decl = origConstant->getAbstractFunctionDecl()) {
2398+
if (auto *nonisolatedAttr =
2399+
decl->getAttrs().getAttribute<NonisolatedAttr>()) {
2400+
if (nonisolatedAttr->isNonSending())
2401+
return ActorIsolation::forCallerIsolationInheriting();
2402+
}
2403+
2404+
if (decl->getAttrs().hasAttribute<ConcurrentAttr>()) {
2405+
return ActorIsolation::forNonisolated(false /*unsafe*/);
2406+
}
2407+
}
2408+
2409+
return getActorIsolationOfContext(origConstant->getInnermostDeclContext());
2410+
}
2411+
2412+
if (constant) {
2413+
// TODO: It should to be possible to `getActorIsolation` if
2414+
// reference is to a decl instead of trying to get isolation
2415+
// from the reference kind, the attributes, or the context.
2416+
2417+
if (constant->kind == SILDeclRef::Kind::Deallocator) {
2418+
return ActorIsolation::forNonisolated(false);
2419+
}
2420+
2421+
if (auto *decl = constant->getAbstractFunctionDecl()) {
2422+
if (auto *nonisolatedAttr =
2423+
decl->getAttrs().getAttribute<NonisolatedAttr>()) {
2424+
if (nonisolatedAttr->isNonSending())
2425+
return ActorIsolation::forCallerIsolationInheriting();
2426+
}
2427+
2428+
if (decl->getAttrs().hasAttribute<ConcurrentAttr>()) {
2429+
return ActorIsolation::forNonisolated(false /*unsafe*/);
2430+
}
2431+
}
2432+
2433+
if (auto *closure = constant->getAbstractClosureExpr()) {
2434+
if (auto isolation = closure->getActorIsolation())
2435+
return isolation;
2436+
}
2437+
2438+
return getActorIsolationOfContext(constant->getInnermostDeclContext());
2439+
}
2440+
2441+
if (substFnInterfaceType->hasExtInfo() &&
2442+
substFnInterfaceType->getExtInfo().getIsolation().isNonIsolatedCaller()) {
2443+
// If our function type is a nonisolated caller and we can not infer from
2444+
// our constant, we must be caller isolation inheriting.
2445+
return ActorIsolation::forCallerIsolationInheriting();
2446+
}
2447+
2448+
return {};
2449+
}
2450+
23892451
/// Create the appropriate SIL function type for the given formal type
23902452
/// and conventions.
23912453
///
@@ -2617,39 +2679,8 @@ static CanSILFunctionType getSILFunctionType(
26172679
SmallBitVector addressableParams;
26182680
SmallBitVector conditionallyAddressableParams;
26192681
{
2620-
std::optional<ActorIsolation> actorIsolation;
2621-
if (constant) {
2622-
// TODO: It should to be possible to `getActorIsolation` if
2623-
// reference is to a decl instead of trying to get isolation
2624-
// from the reference kind, the attributes, or the context.
2625-
2626-
if (constant->kind == SILDeclRef::Kind::Deallocator) {
2627-
actorIsolation = ActorIsolation::forNonisolated(false);
2628-
} else if (auto *decl = constant->getAbstractFunctionDecl()) {
2629-
if (auto *nonisolatedAttr =
2630-
decl->getAttrs().getAttribute<NonisolatedAttr>()) {
2631-
if (nonisolatedAttr->isNonSending())
2632-
actorIsolation = ActorIsolation::forCallerIsolationInheriting();
2633-
} else if (decl->getAttrs().hasAttribute<ConcurrentAttr>()) {
2634-
actorIsolation = ActorIsolation::forNonisolated(false /*unsafe*/);
2635-
}
2636-
} else if (auto *closure = constant->getAbstractClosureExpr()) {
2637-
if (auto isolation = closure->getActorIsolation())
2638-
actorIsolation = isolation;
2639-
}
2640-
2641-
if (!actorIsolation) {
2642-
actorIsolation =
2643-
getActorIsolationOfContext(constant->getInnermostDeclContext());
2644-
}
2645-
} else if (substFnInterfaceType->hasExtInfo() &&
2646-
substFnInterfaceType->getExtInfo()
2647-
.getIsolation()
2648-
.isNonIsolatedCaller()) {
2649-
// If our function type is a nonisolated caller and we can not infer from
2650-
// our constant, we must be caller isolation inheriting.
2651-
actorIsolation = ActorIsolation::forCallerIsolationInheriting();
2652-
}
2682+
auto actorIsolation = getSILFunctionTypeActorIsolation(
2683+
substFnInterfaceType, origConstant, constant);
26532684
DestructureInputs destructurer(expansionContext, TC, conventions,
26542685
foreignInfo, actorIsolation, inputs,
26552686
parameterMap,

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 79 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7663,57 +7663,111 @@ void SILVTable::verify(const SILModule &M) const {
76637663
}
76647664

76657665
/// Verify that a witness table follows invariants.
7666-
void SILWitnessTable::verify(const SILModule &M) const {
7667-
if (!verificationEnabled(M))
7666+
void SILWitnessTable::verify(const SILModule &mod) const {
7667+
if (!verificationEnabled(mod))
76687668
return;
76697669

76707670
if (isDeclaration())
76717671
assert(getEntries().empty() &&
76727672
"A witness table declaration should not have any entries.");
76737673

7674-
for (const Entry &E : getEntries())
7675-
if (E.getKind() == SILWitnessTable::WitnessKind::Method) {
7676-
SILFunction *F = E.getMethodWitness().Witness;
7677-
if (F) {
7678-
// If a SILWitnessTable is going to be serialized, it must only
7679-
// reference public or serializable functions.
7680-
if (isAnySerialized()) {
7681-
assert(F->hasValidLinkageForFragileRef(getSerializedKind()) &&
7682-
"Fragile witness tables should not reference "
7683-
"less visible functions.");
7684-
}
7674+
for (const Entry &entry : getEntries()) {
7675+
if (entry.getKind() != SILWitnessTable::WitnessKind::Method)
7676+
continue;
7677+
7678+
auto *witnessFunction = entry.getMethodWitness().Witness;
7679+
if (!witnessFunction)
7680+
continue;
7681+
7682+
// If a SILWitnessTable is going to be serialized, it must only
7683+
// reference public or serializable functions.
7684+
if (isAnySerialized()) {
7685+
assert(
7686+
witnessFunction->hasValidLinkageForFragileRef(getSerializedKind()) &&
7687+
"Fragile witness tables should not reference "
7688+
"less visible functions.");
7689+
}
76857690

7686-
assert(F->getLoweredFunctionType()->getRepresentation() ==
7691+
assert(witnessFunction->getLoweredFunctionType()->getRepresentation() ==
76877692
SILFunctionTypeRepresentation::WitnessMethod &&
7688-
"Witnesses must have witness_method representation.");
7693+
"Witnesses must have witness_method representation.");
7694+
7695+
if (mod.getStage() != SILStage::Lowered &&
7696+
!mod.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
7697+
// Note the direction of the compatibility check: the witness
7698+
// function must be compatible with being used as the requirement
7699+
// type.
7700+
auto baseInfo = witnessFunction->getModule().Types.getConstantInfo(
7701+
TypeExpansionContext::minimal(),
7702+
entry.getMethodWitness().Requirement);
7703+
SmallString<32> baseName;
7704+
{
7705+
llvm::raw_svector_ostream os(baseName);
7706+
entry.getMethodWitness().Requirement.print(os);
76897707
}
7708+
7709+
SILVerifier(*witnessFunction, /*calleeCache=*/nullptr,
7710+
/*SingleFunction=*/true,
7711+
/*checkLinearLifetime=*/false)
7712+
.requireABICompatibleFunctionTypes(
7713+
witnessFunction->getLoweredFunctionType(),
7714+
baseInfo.getSILType().castTo<SILFunctionType>(),
7715+
"witness table entry for " + baseName + " must be ABI-compatible",
7716+
*witnessFunction);
76907717
}
7718+
}
76917719
}
76927720

76937721
/// Verify that a default witness table follows invariants.
7694-
void SILDefaultWitnessTable::verify(const SILModule &M) const {
7695-
#ifndef NDEBUG
7696-
for (const Entry &E : getEntries()) {
7722+
void SILDefaultWitnessTable::verify(const SILModule &mod) const {
7723+
if (!verificationEnabled(mod))
7724+
return;
7725+
7726+
for (const Entry &entry : getEntries()) {
76977727
// FIXME: associated type witnesses.
7698-
if (!E.isValid() || E.getKind() != SILWitnessTable::Method)
7728+
if (!entry.isValid() || entry.getKind() != SILWitnessTable::Method)
76997729
continue;
77007730

7701-
SILFunction *F = E.getMethodWitness().Witness;
7702-
if (!F)
7731+
auto *witnessFunction = entry.getMethodWitness().Witness;
7732+
if (!witnessFunction)
77037733
continue;
77047734

77057735
#if 0
77067736
// FIXME: For now, all default witnesses are private.
7707-
assert(F->hasValidLinkageForFragileRef(IsSerialized) &&
7737+
assert(witnessFunction->hasValidLinkageForFragileRef(IsSerialized) &&
77087738
"Default witness tables should not reference "
77097739
"less visible functions.");
77107740
#endif
77117741

7712-
assert(F->getLoweredFunctionType()->getRepresentation() ==
7713-
SILFunctionTypeRepresentation::WitnessMethod &&
7742+
assert(witnessFunction->getLoweredFunctionType()->getRepresentation() ==
7743+
SILFunctionTypeRepresentation::WitnessMethod &&
77147744
"Default witnesses must have witness_method representation.");
7745+
7746+
if (mod.getStage() != SILStage::Lowered &&
7747+
!mod.getASTContext().LangOpts.hasFeature(Feature::Embedded)) {
7748+
// Note the direction of the compatibility check: the witness
7749+
// function must be compatible with being used as the requirement
7750+
// type.
7751+
auto baseInfo = witnessFunction->getModule().Types.getConstantInfo(
7752+
TypeExpansionContext::minimal(),
7753+
entry.getMethodWitness().Requirement);
7754+
SmallString<32> baseName;
7755+
{
7756+
llvm::raw_svector_ostream os(baseName);
7757+
entry.getMethodWitness().Requirement.print(os);
7758+
}
7759+
7760+
SILVerifier(*witnessFunction, /*calleeCache=*/nullptr,
7761+
/*SingleFunction=*/true,
7762+
/*checkLinearLifetime=*/false)
7763+
.requireABICompatibleFunctionTypes(
7764+
witnessFunction->getLoweredFunctionType(),
7765+
baseInfo.getSILType().castTo<SILFunctionType>(),
7766+
"default witness table entry for " + baseName +
7767+
" must be ABI-compatible",
7768+
*witnessFunction);
7769+
}
77157770
}
7716-
#endif
77177771
}
77187772

77197773
/// Verify that a global variable follows invariants.

lib/SILGen/SILGenFunction.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2624,8 +2624,7 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
26242624
void collectThunkParams(
26252625
SILLocation loc, SmallVectorImpl<ManagedValue> &params,
26262626
SmallVectorImpl<ManagedValue> *indirectResultParams = nullptr,
2627-
SmallVectorImpl<ManagedValue> *indirectErrorParams = nullptr,
2628-
ThunkGenOptions options = {});
2627+
SmallVectorImpl<ManagedValue> *indirectErrorParams = nullptr);
26292628

26302629
/// Build the type of a function transformation thunk.
26312630
CanSILFunctionType buildThunkType(CanSILFunctionType &sourceType,

0 commit comments

Comments
 (0)