Skip to content

Commit 17522c4

Browse files
author
Gabor Horvath
committed
[SILGen] Fix the type of closure thunks that are passed const reference structs
This PR is another attempt at landing #76903. The changes compared to the original PR: * Instead of increasing the size of SILDeclRef, store the necessary type information in the conversion AST nodes. * The PR above introduced a crash during indexing system modules that references foreign types coming from modules imported as implementation only. These entities are implementation details so they do not need to be included during serialization. This PR adds a test and adds logic to exclude such clang types in the serialization process. rdar://131321096&141786724
1 parent a28515e commit 17522c4

File tree

15 files changed

+333
-53
lines changed

15 files changed

+333
-53
lines changed

include/swift/AST/Expr.h

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "swift/AST/FunctionRefInfo.h"
3030
#include "swift/AST/ProtocolConformanceRef.h"
3131
#include "swift/AST/ThrownErrorDestination.h"
32+
#include "swift/AST/Type.h"
3233
#include "swift/AST/TypeAlignments.h"
3334
#include "swift/Basic/Debug.h"
3435
#include "swift/Basic/InlineBitfield.h"
@@ -3367,9 +3368,8 @@ class UnresolvedTypeConversionExpr : public ImplicitConversionExpr {
33673368
/// FIXME: This should be a CapturingExpr.
33683369
class FunctionConversionExpr : public ImplicitConversionExpr {
33693370
public:
3370-
FunctionConversionExpr(Expr *subExpr, Type type)
3371-
: ImplicitConversionExpr(ExprKind::FunctionConversion, subExpr, type) {}
3372-
3371+
FunctionConversionExpr(Expr *subExpr, Type type);
3372+
33733373
static bool classof(const Expr *E) {
33743374
return E->getKind() == ExprKind::FunctionConversion;
33753375
}
@@ -4290,6 +4290,12 @@ class ClosureExpr : public AbstractClosureExpr {
42904290
/// The body of the closure.
42914291
BraceStmt *Body;
42924292

4293+
/// Used when lowering ClosureExprs to C function pointers.
4294+
/// This is required to access the ClangType from SILDeclRef.
4295+
/// TODO: this will be redundant after we preserve ClangTypes
4296+
/// in the canonical types.
4297+
FunctionConversionExpr *ConvertedTo;
4298+
42934299
friend class GlobalActorAttributeRequest;
42944300

42954301
bool hasNoGlobalActorAttribute() const {
@@ -4301,19 +4307,19 @@ class ClosureExpr : public AbstractClosureExpr {
43014307
}
43024308

43034309
public:
4304-
ClosureExpr(const DeclAttributes &attributes,
4305-
SourceRange bracketRange, VarDecl *capturedSelfDecl,
4306-
ParameterList *params, SourceLoc asyncLoc, SourceLoc throwsLoc,
4307-
TypeExpr *thrownType, SourceLoc arrowLoc, SourceLoc inLoc,
4308-
TypeExpr *explicitResultType, DeclContext *parent)
4309-
: AbstractClosureExpr(ExprKind::Closure, Type(), /*Implicit=*/false,
4310-
parent),
4311-
Attributes(attributes), BracketRange(bracketRange),
4312-
CapturedSelfDecl(capturedSelfDecl),
4313-
AsyncLoc(asyncLoc), ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc),
4314-
InLoc(inLoc), ThrownType(thrownType),
4315-
ExplicitResultTypeAndBodyState(explicitResultType, BodyState::Parsed),
4316-
Body(nullptr) {
4310+
ClosureExpr(const DeclAttributes &attributes, SourceRange bracketRange,
4311+
VarDecl *capturedSelfDecl, ParameterList *params,
4312+
SourceLoc asyncLoc, SourceLoc throwsLoc, TypeExpr *thrownType,
4313+
SourceLoc arrowLoc, SourceLoc inLoc, TypeExpr *explicitResultType,
4314+
DeclContext *parent)
4315+
: AbstractClosureExpr(ExprKind::Closure, Type(), /*Implicit=*/false,
4316+
parent),
4317+
Attributes(attributes), BracketRange(bracketRange),
4318+
CapturedSelfDecl(capturedSelfDecl), AsyncLoc(asyncLoc),
4319+
ThrowsLoc(throwsLoc), ArrowLoc(arrowLoc), InLoc(inLoc),
4320+
ThrownType(thrownType),
4321+
ExplicitResultTypeAndBodyState(explicitResultType, BodyState::Parsed),
4322+
Body(nullptr), ConvertedTo(nullptr) {
43174323
setParameterList(params);
43184324
Bits.ClosureExpr.HasAnonymousClosureVars = false;
43194325
Bits.ClosureExpr.ImplicitSelfCapture = false;
@@ -4528,6 +4534,9 @@ class ClosureExpr : public AbstractClosureExpr {
45284534
ExplicitResultTypeAndBodyState.setInt(v);
45294535
}
45304536

4537+
const FunctionConversionExpr *getConvertedTo() const { return ConvertedTo; }
4538+
void setConvertedTo(FunctionConversionExpr *e) { ConvertedTo = e; }
4539+
45314540
static bool classof(const Expr *E) {
45324541
return E->getKind() == ExprKind::Closure;
45334542
}

include/swift/SIL/SILDeclRef.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ namespace llvm {
3434
class raw_ostream;
3535
}
3636

37+
namespace clang {
38+
class Type;
39+
}
40+
3741
namespace swift {
3842
enum class EffectsKind : uint8_t;
3943
class AbstractFunctionDecl;
@@ -261,11 +265,9 @@ struct SILDeclRef {
261265
/// for the containing ClassDecl.
262266
/// - If 'loc' is a global VarDecl, this returns its GlobalAccessor
263267
/// SILDeclRef.
264-
explicit SILDeclRef(
265-
Loc loc,
266-
bool isForeign = false,
267-
bool isDistributed = false,
268-
bool isDistributedLocal = false);
268+
explicit SILDeclRef(Loc loc, bool isForeign = false,
269+
bool isDistributed = false,
270+
bool isDistributedLocal = false);
269271

270272
/// See above put produces a prespecialization according to the signature.
271273
explicit SILDeclRef(Loc loc, GenericSignature prespecializationSig);

lib/AST/Expr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,6 +1456,16 @@ DestructureTupleExpr::create(ASTContext &ctx,
14561456
srcExpr, dstExpr, ty);
14571457
}
14581458

1459+
FunctionConversionExpr::FunctionConversionExpr(Expr *subExpr, Type type)
1460+
: ImplicitConversionExpr(ExprKind::FunctionConversion, subExpr, type) {
1461+
while (auto *PE = dyn_cast<ParenExpr>(subExpr))
1462+
subExpr = PE->getSubExpr();
1463+
if (auto *CLE = dyn_cast<CaptureListExpr>(subExpr))
1464+
subExpr = CLE->getClosureBody();
1465+
if (auto *CE = dyn_cast<ClosureExpr>(subExpr))
1466+
CE->setConvertedTo(this);
1467+
}
1468+
14591469
SourceRange TupleExpr::getSourceRange() const {
14601470
auto start = LParenLoc;
14611471
if (start.isInvalid()) {

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
//
1717
//===----------------------------------------------------------------------===//
1818

19+
#include "swift/AST/Expr.h"
20+
#include "swift/AST/Type.h"
1921
#define DEBUG_TYPE "libsil"
2022

2123
#include "swift/AST/AnyFunctionRef.h"
@@ -4321,12 +4323,10 @@ static CanSILFunctionType getUncachedSILFunctionTypeForConstant(
43214323
// The type of the native-to-foreign thunk for a swift closure.
43224324
if (constant.isForeign && constant.hasClosureExpr() &&
43234325
shouldStoreClangType(TC.getDeclRefRepresentation(constant))) {
4324-
auto clangType = TC.Context.getClangFunctionType(
4325-
origLoweredInterfaceType->getParams(),
4326-
origLoweredInterfaceType->getResult(),
4327-
FunctionTypeRepresentation::CFunctionPointer);
4328-
AbstractionPattern pattern =
4329-
AbstractionPattern(origLoweredInterfaceType, clangType);
4326+
assert(!extInfoBuilder.getClangTypeInfo().empty() &&
4327+
"clang type not found");
4328+
AbstractionPattern pattern = AbstractionPattern(
4329+
origLoweredInterfaceType, extInfoBuilder.getClangTypeInfo().getType());
43304330
return getSILFunctionTypeForAbstractCFunction(
43314331
TC, pattern, origLoweredInterfaceType, extInfoBuilder, constant);
43324332
}
@@ -4834,9 +4834,22 @@ getAbstractionPatternForConstant(ASTContext &ctx, SILDeclRef constant,
48344834
if (!constant.isForeign)
48354835
return AbstractionPattern(fnType);
48364836

4837+
if (const auto *closure = dyn_cast_or_null<ClosureExpr>(
4838+
constant.loc.dyn_cast<AbstractClosureExpr *>())) {
4839+
if (const auto *convertedTo = closure->getConvertedTo()) {
4840+
auto clangInfo = convertedTo->getType()
4841+
->castTo<AnyFunctionType>()
4842+
->getExtInfo()
4843+
.getClangTypeInfo();
4844+
if (!clangInfo.empty())
4845+
return AbstractionPattern(fnType, clangInfo.getType());
4846+
}
4847+
}
4848+
48374849
auto bridgedFn = getBridgedFunction(constant);
48384850
if (!bridgedFn)
48394851
return AbstractionPattern(fnType);
4852+
48404853
const clang::Decl *clangDecl = bridgedFn->getClangDecl();
48414854
if (!clangDecl)
48424855
return AbstractionPattern(fnType);

lib/SILGen/SILGenBridging.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,8 +1315,9 @@ static SILValue emitObjCUnconsumedArgument(SILGenFunction &SGF,
13151315
SILLocation loc,
13161316
SILValue arg) {
13171317
auto &lowering = SGF.getTypeLowering(arg->getType());
1318-
// If address-only, make a +1 copy and operate on that.
1319-
if (lowering.isAddressOnly() && SGF.useLoweredAddresses()) {
1318+
// If arg is non-trivial and has an address type, make a +1 copy and operate
1319+
// on that.
1320+
if (!lowering.isTrivial() && arg->getType().isAddress()) {
13201321
auto tmp = SGF.emitTemporaryAllocation(loc, arg->getType().getObjectType());
13211322
SGF.B.createCopyAddr(loc, arg, tmp, IsNotTake, IsInitialization);
13221323
return tmp;
@@ -1453,6 +1454,11 @@ emitObjCThunkArguments(SILGenFunction &SGF, SILLocation loc, SILDeclRef thunk,
14531454
auto buf = SGF.emitTemporaryAllocation(loc, native.getType());
14541455
native.forwardInto(SGF, loc, buf);
14551456
native = SGF.emitManagedBufferWithCleanup(buf);
1457+
} else if (!fnConv.isSILIndirect(nativeInputs[i]) &&
1458+
native.getType().isAddress()) {
1459+
// Load the value if the argument has an address type and the native
1460+
// function expects the argument to be passed directly.
1461+
native = SGF.emitManagedLoadCopy(loc, native.getValue());
14561462
}
14571463

14581464
if (nativeInputs[i].isConsumedInCaller()) {

lib/SILGen/SILGenExpr.cpp

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,7 +1733,19 @@ static ManagedValue convertCFunctionSignature(SILGenFunction &SGF,
17331733
FunctionConversionExpr *e,
17341734
SILType loweredResultTy,
17351735
llvm::function_ref<ManagedValue ()> fnEmitter) {
1736-
SILType loweredDestTy = SGF.getLoweredType(e->getType());
1736+
SILType loweredDestTy;
1737+
auto destTy = e->getType();
1738+
auto clangInfo =
1739+
destTy->castTo<AnyFunctionType>()->getExtInfo().getClangTypeInfo();
1740+
if (clangInfo.empty())
1741+
loweredDestTy = SGF.getLoweredType(destTy);
1742+
else
1743+
// This won't be necessary after we stop dropping clang types when
1744+
// canonicalizing function types.
1745+
loweredDestTy = SGF.getLoweredType(
1746+
AbstractionPattern(destTy->getCanonicalType(), clangInfo.getType()),
1747+
destTy);
1748+
17371749
ManagedValue result;
17381750

17391751
// We're converting between C function pointer types. They better be
@@ -1804,20 +1816,20 @@ ManagedValue emitCFunctionPointer(SILGenFunction &SGF,
18041816
#endif
18051817
semanticExpr = conv->getSubExpr()->getSemanticsProvidingExpr();
18061818
}
1807-
1819+
18081820
if (auto declRef = dyn_cast<DeclRefExpr>(semanticExpr)) {
18091821
setLocFromConcreteDeclRef(declRef->getDeclRef());
18101822
} else if (auto memberRef = dyn_cast<MemberRefExpr>(semanticExpr)) {
18111823
setLocFromConcreteDeclRef(memberRef->getMember());
18121824
} else if (isAnyClosureExpr(semanticExpr)) {
1813-
(void) emitAnyClosureExpr(SGF, semanticExpr,
1814-
[&](AbstractClosureExpr *closure) {
1815-
// Emit the closure body.
1816-
SGF.SGM.emitClosure(closure, SGF.getClosureTypeInfo(closure));
1825+
(void)emitAnyClosureExpr(
1826+
SGF, semanticExpr, [&](AbstractClosureExpr *closure) {
1827+
// Emit the closure body.
1828+
SGF.SGM.emitClosure(closure, SGF.getClosureTypeInfo(closure));
18171829

1818-
loc = closure;
1819-
return ManagedValue();
1820-
});
1830+
loc = closure;
1831+
return ManagedValue();
1832+
});
18211833
} else {
18221834
llvm_unreachable("c function pointer converted from a non-concrete decl ref");
18231835
}

lib/Serialization/Deserialization.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8495,9 +8495,6 @@ class SwiftToClangBasicReader :
84958495

84968496
llvm::Expected<const clang::Type *>
84978497
ModuleFile::getClangType(ClangTypeID TID) {
8498-
if (!getContext().LangOpts.UseClangFunctionTypes)
8499-
return nullptr;
8500-
85018498
if (TID == 0)
85028499
return nullptr;
85038500

lib/Serialization/Serialization.cpp

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/ASTMangler.h"
1818
#include "swift/AST/ASTVisitor.h"
1919
#include "swift/AST/AutoDiff.h"
20+
#include "swift/AST/Decl.h"
2021
#include "swift/AST/DiagnosticsCommon.h"
2122
#include "swift/AST/DiagnosticsSema.h"
2223
#include "swift/AST/Expr.h"
@@ -41,6 +42,7 @@
4142
#include "swift/AST/SynthesizedFileUnit.h"
4243
#include "swift/AST/TypeCheckRequests.h"
4344
#include "swift/AST/TypeVisitor.h"
45+
#include "swift/AST/Types.h"
4446
#include "swift/Basic/Assertions.h"
4547
#include "swift/Basic/Defer.h"
4648
#include "swift/Basic/FileSystem.h"
@@ -5546,6 +5548,31 @@ static TypeAliasDecl *findTypeAliasForBuiltin(ASTContext &Ctx, Type T) {
55465548
return cast<TypeAliasDecl>(CurModuleResults[0]);
55475549
}
55485550

5551+
namespace {
5552+
struct ImplementationOnylWalker : TypeWalker {
5553+
bool hadImplementationOnlyDecl = false;
5554+
const ModuleDecl *currentModule;
5555+
ImplementationOnylWalker(const ModuleDecl *M) : currentModule(M) {}
5556+
Action walkToTypePre(Type ty) override {
5557+
if (auto *typeAlias = dyn_cast<TypeAliasType>(ty)) {
5558+
if (importedImplementationOnly(typeAlias->getDecl()))
5559+
return Action::Stop;
5560+
} else if (auto *nominal = ty->getAs<NominalType>()) {
5561+
if (importedImplementationOnly(nominal->getDecl()))
5562+
return Action::Stop;
5563+
}
5564+
return Action::Continue;
5565+
}
5566+
bool importedImplementationOnly(const Decl *D) {
5567+
if (currentModule->isImportedImplementationOnly(D->getModuleContext())) {
5568+
hadImplementationOnlyDecl = true;
5569+
return true;
5570+
}
5571+
return false;
5572+
}
5573+
};
5574+
} // namespace
5575+
55495576
class Serializer::TypeSerializer : public TypeVisitor<TypeSerializer> {
55505577
Serializer &S;
55515578

@@ -5899,10 +5926,19 @@ class Serializer::TypeSerializer : public TypeVisitor<TypeSerializer> {
58995926
using namespace decls_block;
59005927

59015928
auto resultType = S.addTypeRef(fnTy->getResult());
5902-
auto clangType =
5903-
S.getASTContext().LangOpts.UseClangFunctionTypes
5904-
? S.addClangTypeRef(fnTy->getClangTypeInfo().getType())
5905-
: ClangTypeID(0);
5929+
bool shouldSerializeClangType = true;
5930+
if (S.hadImplementationOnlyImport && S.M) {
5931+
// Deserializing clang types from implementation only modules could crash
5932+
// as the transitive clang module might not be available to retrieve the
5933+
// declarations from.
5934+
ImplementationOnylWalker walker{S.M};
5935+
Type(const_cast<FunctionType *>(fnTy)).walk(walker);
5936+
if (walker.hadImplementationOnlyDecl)
5937+
shouldSerializeClangType = false;
5938+
}
5939+
auto clangType = shouldSerializeClangType
5940+
? S.addClangTypeRef(fnTy->getClangTypeInfo().getType())
5941+
: ClangTypeID(0);
59065942

59075943
auto isolation = encodeIsolation(fnTy->getIsolation());
59085944

@@ -6984,8 +7020,13 @@ void Serializer::writeAST(ModuleOrSourceFile DC) {
69847020
nextFile->getTopLevelDeclsWithAuxiliaryDecls(fileDecls);
69857021

69867022
for (auto D : fileDecls) {
6987-
if (isa<ImportDecl>(D) || isa<MacroExpansionDecl>(D) ||
6988-
isa<TopLevelCodeDecl>(D) || isa<UsingDecl>(D)) {
7023+
if (const auto *ID = dyn_cast<ImportDecl>(D)) {
7024+
if (ID->getAttrs().hasAttribute<ImplementationOnlyAttr>())
7025+
hadImplementationOnlyImport = true;
7026+
continue;
7027+
}
7028+
if (isa<MacroExpansionDecl>(D) || isa<TopLevelCodeDecl>(D) ||
7029+
isa<UsingDecl>(D)) {
69897030
continue;
69907031
}
69917032

lib/Serialization/Serialization.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ class Serializer : public SerializerBase {
116116
/// an error in the AST.
117117
bool hadError = false;
118118

119+
bool hadImplementationOnlyImport = false;
120+
119121
/// Helper for serializing entities in the AST block object graph.
120122
///
121123
/// Keeps track of assigning IDs to newly-seen entities, and collecting

test/Interop/Cxx/class/Inputs/closure.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ struct NonTrivial {
1010
int *p;
1111
};
1212

13+
struct Trivial {
14+
int i;
15+
};
16+
1317
void cfunc(void (^ _Nonnull block)(NonTrivial)) noexcept {
1418
block(NonTrivial());
1519
}
@@ -75,4 +79,13 @@ inline void releaseSharedRef(SharedRef *_Nonnull x) {
7579
}
7680
}
7781

82+
void cfuncConstRefNonTrivial(void (*_Nonnull)(const NonTrivial &));
83+
void cfuncConstRefTrivial(void (*_Nonnull)(const Trivial &));
84+
void blockConstRefNonTrivial(void (^_Nonnull)(const NonTrivial &));
85+
void blockConstRefTrivial(void (^_Nonnull)(const Trivial &));
86+
#if __OBJC__
87+
void cfuncConstRefStrong(void (*_Nonnull)(const ARCStrong &));
88+
void blockConstRefStrong(void (^_Nonnull)(const ARCStrong &));
89+
#endif
90+
7891
#endif // __CLOSURE__

0 commit comments

Comments
 (0)