Skip to content

Commit 196f358

Browse files
[AST] Add ClangTypeConverter, computing C types for FunctionTypes.
Note: The change in ASTBuilder::createFunctionType is functionally minor, but we need the FunctionType::Params computed _before_ the ExtInfo, so we need to shuffle a bunch of code around.
1 parent 8021795 commit 196f358

19 files changed

+1048
-60
lines changed

include/swift/AST/ASTContext.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "swift/AST/Identifier.h"
2323
#include "swift/AST/SearchPathOptions.h"
2424
#include "swift/AST/Type.h"
25+
#include "swift/AST/Types.h"
2526
#include "swift/AST/TypeAlignments.h"
2627
#include "swift/Basic/LangOptions.h"
2728
#include "swift/Basic/Malloc.h"
@@ -557,6 +558,19 @@ class ASTContext final {
557558
Type getBridgedToObjC(const DeclContext *dc, Type type,
558559
Type *bridgedValueType = nullptr) const;
559560

561+
/// Get the Clang type corresponding to a Swift function type.
562+
///
563+
/// \param params The function parameters.
564+
/// \param resultTy The Swift result type.
565+
/// \param incompleteExtInfo Used to convey escaping and throwing
566+
/// information, in case it is needed.
567+
/// \param trueRep The actual calling convention, which must be C-compatible.
568+
/// The calling convention in \p incompleteExtInfo is ignored.
569+
const clang::Type *
570+
getClangFunctionType(ArrayRef<AnyFunctionType::Param> params, Type resultTy,
571+
const FunctionType::ExtInfo incompleteExtInfo,
572+
FunctionTypeRepresentation trueRep);
573+
560574
/// Determine whether the given Swift type is representable in a
561575
/// given foreign language.
562576
ForeignRepresentationInfo

include/swift/AST/ClangModuleLoader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class ASTContext;
2020
class CompilerInstance;
2121
class Preprocessor;
2222
class Sema;
23+
class TargetInfo;
2324
} // namespace clang
2425

2526
namespace swift {
@@ -46,6 +47,7 @@ class ClangModuleLoader : public ModuleLoader {
4647
using ModuleLoader::ModuleLoader;
4748

4849
public:
50+
virtual clang::TargetInfo &getTargetInfo() const = 0;
4951
virtual clang::ASTContext &getClangASTContext() const = 0;
5052
virtual clang::Preprocessor &getClangPreprocessor() const = 0;
5153
virtual clang::Sema &getClangSema() const = 0;

include/swift/AST/Types.h

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2975,6 +2975,11 @@ class AnyFunctionType : public TypeBase {
29752975
return Representation(rawRep);
29762976
}
29772977

2978+
/// Return the underlying Uncommon value if it is not the default value.
2979+
Optional<Uncommon> getUncommonInfo() const {
2980+
return Other.empty() ? Optional<Uncommon>() : Other;
2981+
}
2982+
29782983
bool hasSelfParam() const {
29792984
switch (getSILRepresentation()) {
29802985
case SILFunctionTypeRepresentation::Thick:
@@ -3060,12 +3065,16 @@ class AnyFunctionType : public TypeBase {
30603065
};
30613066

30623067
protected:
3068+
/// Create an AnyFunctionType.
3069+
///
3070+
/// Subclasses are responsible for storing and retrieving the
3071+
/// ExtInfo::Uncommon value if one is present.
30633072
AnyFunctionType(TypeKind Kind, const ASTContext *CanTypeContext,
30643073
Type Output, RecursiveTypeProperties properties,
30653074
unsigned NumParams, ExtInfo Info)
30663075
: TypeBase(Kind, CanTypeContext, properties), Output(Output) {
30673076
Bits.AnyFunctionType.ExtInfoBits = Info.Bits;
3068-
Bits.AnyFunctionType.HasUncommonInfo = false;
3077+
Bits.AnyFunctionType.HasUncommonInfo = Info.getUncommonInfo().hasValue();
30693078
Bits.AnyFunctionType.NumParams = NumParams;
30703079
assert(Bits.AnyFunctionType.NumParams == NumParams && "Params dropped!");
30713080
// The use of both assert() and static_assert() is intentional.
@@ -3119,9 +3128,14 @@ class AnyFunctionType : public TypeBase {
31193128
return ExtInfo(Bits.AnyFunctionType.ExtInfoBits, getClangFunctionType());
31203129
}
31213130

3122-
ExtInfo getCanonicalExtInfo() const {
3131+
/// Get the canonical ExtInfo for the function type.
3132+
///
3133+
/// The parameter useClangFunctionType is present only for staging purposes.
3134+
/// In the future, we will always use the canonical clang function type.
3135+
ExtInfo getCanonicalExtInfo(bool useClangFunctionType) const {
31233136
return ExtInfo(Bits.AnyFunctionType.ExtInfoBits,
3124-
getCanonicalClangFunctionType());
3137+
useClangFunctionType ? getCanonicalClangFunctionType()
3138+
: nullptr);
31253139
}
31263140

31273141
/// Get the representation of the function type.
@@ -3187,16 +3201,25 @@ END_CAN_TYPE_WRAPPER(AnyFunctionType, Type)
31873201
inline AnyFunctionType::CanYield AnyFunctionType::Yield::getCanonical() const {
31883202
return CanYield(getType()->getCanonicalType(), getFlags());
31893203
}
3190-
31913204
/// FunctionType - A monomorphic function type, specified with an arrow.
31923205
///
31933206
/// For example:
31943207
/// let x : (Float, Int) -> Int
31953208
class FunctionType final : public AnyFunctionType,
31963209
public llvm::FoldingSetNode,
3197-
private llvm::TrailingObjects<FunctionType, AnyFunctionType::Param> {
3210+
private llvm::TrailingObjects<FunctionType, AnyFunctionType::Param,
3211+
AnyFunctionType::ExtInfo::Uncommon> {
31983212
friend TrailingObjects;
31993213

3214+
3215+
size_t numTrailingObjects(OverloadToken<AnyFunctionType::Param>) const {
3216+
return getNumParams();
3217+
}
3218+
3219+
size_t numTrailingObjects(OverloadToken<ExtInfo::Uncommon>) const {
3220+
return hasClangFunctionType() ? 1 : 0;
3221+
}
3222+
32003223
public:
32013224
/// 'Constructor' Factory Function
32023225
static FunctionType *get(ArrayRef<Param> params, Type result,
@@ -3207,6 +3230,14 @@ class FunctionType final : public AnyFunctionType,
32073230
return {getTrailingObjects<Param>(), getNumParams()};
32083231
}
32093232

3233+
const clang::Type *getClangFunctionType() const {
3234+
if (!hasClangFunctionType())
3235+
return nullptr;
3236+
auto *type = getTrailingObjects<ExtInfo::Uncommon>()->ClangFunctionType;
3237+
assert(type && "If the pointer was null, we shouldn't have stored it.");
3238+
return type;
3239+
}
3240+
32103241
void Profile(llvm::FoldingSetNodeID &ID) {
32113242
Profile(ID, getParams(), getResult(), getExtInfo());
32123243
}

include/swift/Basic/LangOptions.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,13 @@ namespace swift {
219219
/// Build the ASTScope tree lazily
220220
bool LazyASTScopes = true;
221221

222+
/// Use Clang function types for computing canonical types.
223+
/// If this option is false, the clang function types will still be computed
224+
/// but will not be used for checking type equality.
225+
/// FIXME: [clang-function-type-serialization] This option should be turned
226+
/// on once we start serializing clang function types.
227+
bool UseClangFunctionTypes = false;
228+
222229
/// Whether to use the import as member inference system
223230
///
224231
/// When importing a global, try to infer whether we can import it as a

include/swift/ClangImporter/ClangImporter.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ class ClangImporter final : public ClangModuleLoader {
362362

363363
void verifyAllModules() override;
364364

365-
clang::TargetInfo &getTargetInfo() const;
365+
clang::TargetInfo &getTargetInfo() const override;
366366
clang::ASTContext &getClangASTContext() const override;
367367
clang::Preprocessor &getClangPreprocessor() const override;
368368
clang::Sema &getClangSema() const override;

include/swift/Option/FrontendOptions.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ def warn_if_astscope_lookup : Flag<["-"], "warn-if-astscope-lookup">,
151151
def lazy_astscopes : Flag<["-"], "lazy-astscopes">,
152152
HelpText<"Build ASTScopes lazily">;
153153

154+
def use_clang_function_types : Flag<["-"], "use-clang-function-types">,
155+
HelpText<"Use stored Clang function types for computing canonical types.">;
156+
154157
def print_clang_stats : Flag<["-"], "print-clang-stats">,
155158
HelpText<"Print Clang importer statistics">;
156159

lib/AST/ASTContext.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "swift/AST/ASTContext.h"
18+
#include "ClangTypeConverter.h"
1819
#include "ForeignRepresentationInfo.h"
1920
#include "SubstitutionMapStorage.h"
2021
#include "swift/AST/ClangModuleLoader.h"
@@ -463,6 +464,8 @@ struct ASTContext::Implementation {
463464
RC<syntax::SyntaxArena> TheSyntaxArena;
464465

465466
llvm::DenseMap<OverrideSignatureKey, GenericSignature> overrideSigCache;
467+
468+
Optional<ClangTypeConverter> Converter;
466469
};
467470

468471
ASTContext::Implementation::Implementation()
@@ -2997,11 +3000,17 @@ FunctionType *FunctionType::get(ArrayRef<AnyFunctionType::Param> params,
29973000
return funcTy;
29983001
}
29993002

3000-
void *mem = ctx.Allocate(sizeof(FunctionType) +
3001-
sizeof(AnyFunctionType::Param) * params.size(),
3002-
alignof(FunctionType), arena);
3003+
Optional<ExtInfo::Uncommon> uncommon = info.getUncommonInfo();
3004+
3005+
size_t allocSize =
3006+
totalSizeToAlloc<AnyFunctionType::Param, ExtInfo::Uncommon>(
3007+
params.size(), uncommon.hasValue() ? 1 : 0);
3008+
void *mem = ctx.Allocate(allocSize, alignof(FunctionType), arena);
30033009

30043010
bool isCanonical = isFunctionTypeCanonical(params, result);
3011+
if (uncommon.hasValue())
3012+
isCanonical &= uncommon->ClangFunctionType->isCanonicalUnqualified();
3013+
30053014
auto funcTy = new (mem) FunctionType(params, result, info,
30063015
isCanonical ? &ctx : nullptr,
30073016
properties);
@@ -3018,6 +3027,9 @@ FunctionType::FunctionType(ArrayRef<AnyFunctionType::Param> params,
30183027
output, properties, params.size(), info) {
30193028
std::uninitialized_copy(params.begin(), params.end(),
30203029
getTrailingObjects<AnyFunctionType::Param>());
3030+
Optional<ExtInfo::Uncommon> uncommon = info.getUncommonInfo();
3031+
if (uncommon.hasValue())
3032+
*getTrailingObjects<ExtInfo::Uncommon>() = uncommon.getValue();
30213033
}
30223034

30233035
void GenericFunctionType::Profile(llvm::FoldingSetNodeID &ID,
@@ -4323,6 +4335,19 @@ Type ASTContext::getBridgedToObjC(const DeclContext *dc, Type type,
43234335
return Type();
43244336
}
43254337

4338+
const clang::Type *
4339+
ASTContext::getClangFunctionType(ArrayRef<AnyFunctionType::Param> params,
4340+
Type resultTy,
4341+
FunctionType::ExtInfo incompleteExtInfo,
4342+
FunctionTypeRepresentation trueRep) {
4343+
auto &impl = getImpl();
4344+
if (!impl.Converter) {
4345+
auto *cml = getClangModuleLoader();
4346+
impl.Converter.emplace(*this, cml->getClangASTContext(), LangOpts.Target);
4347+
}
4348+
return impl.Converter.getValue().getFunctionType(params, resultTy, trueRep);
4349+
}
4350+
43264351
CanGenericSignature ASTContext::getSingleGenericParameterSignature() const {
43274352
if (auto theSig = getImpl().SingleGenericParameterSignature)
43284353
return theSig;

lib/AST/ASTDemangler.cpp

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -348,33 +348,6 @@ Type ASTBuilder::createTupleType(ArrayRef<Type> eltTypes,
348348
Type ASTBuilder::createFunctionType(
349349
ArrayRef<Demangle::FunctionParam<Type>> params,
350350
Type output, FunctionTypeFlags flags) {
351-
FunctionTypeRepresentation representation;
352-
switch (flags.getConvention()) {
353-
case FunctionMetadataConvention::Swift:
354-
representation = FunctionTypeRepresentation::Swift;
355-
break;
356-
case FunctionMetadataConvention::Block:
357-
representation = FunctionTypeRepresentation::Block;
358-
break;
359-
case FunctionMetadataConvention::Thin:
360-
representation = FunctionTypeRepresentation::Thin;
361-
break;
362-
case FunctionMetadataConvention::CFunctionPointer:
363-
representation = FunctionTypeRepresentation::CFunctionPointer;
364-
break;
365-
}
366-
367-
auto einfo = AnyFunctionType::ExtInfo(representation,
368-
/*throws*/ flags.throws());
369-
370-
if (representation == FunctionTypeRepresentation::Swift ||
371-
representation == FunctionTypeRepresentation::Block) {
372-
if (flags.isEscaping())
373-
einfo = einfo.withNoEscape(false);
374-
else
375-
einfo = einfo.withNoEscape(true);
376-
}
377-
378351
// The result type must be materializable.
379352
if (!output->isMaterializable()) return Type();
380353

@@ -397,6 +370,42 @@ Type ASTBuilder::createFunctionType(
397370
funcParams.push_back(AnyFunctionType::Param(type, label, parameterFlags));
398371
}
399372

373+
FunctionTypeRepresentation representation;
374+
switch (flags.getConvention()) {
375+
case FunctionMetadataConvention::Swift:
376+
representation = FunctionTypeRepresentation::Swift;
377+
break;
378+
case FunctionMetadataConvention::Block:
379+
representation = FunctionTypeRepresentation::Block;
380+
break;
381+
case FunctionMetadataConvention::Thin:
382+
representation = FunctionTypeRepresentation::Thin;
383+
break;
384+
case FunctionMetadataConvention::CFunctionPointer:
385+
representation = FunctionTypeRepresentation::CFunctionPointer;
386+
break;
387+
}
388+
389+
auto noescape =
390+
(representation == FunctionTypeRepresentation::Swift
391+
|| representation == FunctionTypeRepresentation::Block)
392+
&& !flags.isEscaping();
393+
394+
FunctionType::ExtInfo incompleteExtInfo(
395+
FunctionTypeRepresentation::Swift,
396+
noescape, flags.throws(),
397+
DifferentiabilityKind::NonDifferentiable,
398+
/*clangFunctionType*/nullptr);
399+
400+
const clang::Type *clangFunctionType = nullptr;
401+
if (representation == FunctionTypeRepresentation::CFunctionPointer)
402+
clangFunctionType = Ctx.getClangFunctionType(funcParams, output,
403+
incompleteExtInfo,
404+
representation);
405+
406+
auto einfo = incompleteExtInfo.withRepresentation(representation)
407+
.withClangFunctionType(clangFunctionType);
408+
400409
return FunctionType::get(funcParams, output, einfo);
401410
}
402411

lib/AST/ASTDumper.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3608,6 +3608,12 @@ namespace {
36083608

36093609
OS << "\n";
36103610
Indent += 2;
3611+
if (auto *cty = T->getClangFunctionType()) {
3612+
std::string s;
3613+
llvm::raw_string_ostream os(s);
3614+
cty->dump(os);
3615+
printField("clang_type", os.str());
3616+
}
36113617
printAnyFunctionParams(T->getParams(), "input");
36123618
Indent -=2;
36133619
printRec("output", T->getResult());

lib/AST/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ add_swift_host_library(swiftAST STATIC
3434
AvailabilitySpec.cpp
3535
Builtins.cpp
3636
CaptureInfo.cpp
37+
ClangTypeConverter.cpp
3738
ConcreteDeclRef.cpp
3839
ConformanceLookupTable.cpp
3940
Decl.cpp

0 commit comments

Comments
 (0)