Skip to content

Commit 9660447

Browse files
[AST] Add printing for Clang function types in the AST.
1 parent afc6332 commit 9660447

File tree

17 files changed

+160
-14
lines changed

17 files changed

+160
-14
lines changed

include/swift/AST/ASTPrinter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#define SWIFT_AST_ASTPRINTER_H
1515

1616
#include "swift/Basic/LLVM.h"
17+
#include "swift/Basic/QuotedString.h"
1718
#include "swift/Basic/UUID.h"
1819
#include "swift/AST/Identifier.h"
1920
#include "llvm/ADT/StringRef.h"
@@ -185,6 +186,8 @@ class ASTPrinter {
185186
return *this;
186187
}
187188

189+
ASTPrinter &operator<<(QuotedString s);
190+
188191
ASTPrinter &operator<<(unsigned long long N);
189192
ASTPrinter &operator<<(UUID UU);
190193

include/swift/AST/ClangModuleLoader.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ class ClangModuleLoader : public ModuleLoader {
107107
/// Returns null if there was a parsing failure.
108108
virtual const clang::Type *parseClangFunctionType(StringRef type,
109109
SourceLoc loc) const = 0;
110+
111+
/// Print the Clang type.
112+
virtual void printClangType(const clang::Type *type,
113+
llvm::raw_ostream &os) const = 0;
110114
};
111115

112116
} // namespace swift

include/swift/AST/PrintOptions.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,21 @@ struct PrintOptions {
306306
/// List of decls that should be printed even if they are implicit and \c SkipImplicit is set to true.
307307
std::vector<const Decl*> TreatAsExplicitDeclList;
308308

309+
enum class FunctionRepresentationMode : uint8_t {
310+
/// Print the entire convention, including an arguments.
311+
/// For example, this will print a cType argument label if applicable.
312+
Full,
313+
/// Print only the name of the convention, skipping extra argument labels.
314+
NameOnly,
315+
/// Skip printing the @convention(..) altogether.
316+
None
317+
};
318+
309319
/// Whether to print function @convention attribute on function types.
310-
bool PrintFunctionRepresentationAttrs = true;
320+
// FIXME: [clang-function-type-serialization] Once we start serializing Clang
321+
// types, we should also start printing the full type in the swiftinterface.
322+
FunctionRepresentationMode PrintFunctionRepresentationAttrs =
323+
FunctionRepresentationMode::NameOnly;
311324

312325
/// Whether to print storage representation attributes on types, e.g.
313326
/// '@sil_weak', '@sil_unmanaged'.
@@ -502,7 +515,8 @@ struct PrintOptions {
502515
/// consistent and well-formed.
503516
///
504517
/// \see swift::emitSwiftInterface
505-
static PrintOptions printSwiftInterfaceFile(bool preferTypeRepr);
518+
static PrintOptions printSwiftInterfaceFile(bool preferTypeRepr,
519+
bool printFullConvention);
506520

507521
/// Retrieve the set of options suitable for "Generated Interfaces", which
508522
/// are a prettified representation of the public API of a module, to be
@@ -585,7 +599,8 @@ struct PrintOptions {
585599
PO.SkipUnderscoredKeywords = true;
586600
PO.EnumRawValues = EnumRawValueMode::Print;
587601
PO.PrintImplicitAttrs = false;
588-
PO.PrintFunctionRepresentationAttrs = false;
602+
PO.PrintFunctionRepresentationAttrs =
603+
PrintOptions::FunctionRepresentationMode::None;
589604
PO.PrintDocumentationComments = false;
590605
PO.ExcludeAttrList.push_back(DAK_Available);
591606
PO.SkipPrivateStdlibDecls = true;

include/swift/AST/Types.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class AssociatedTypeDecl;
5959
class ASTContext;
6060
enum BufferPointerTypeKind : unsigned;
6161
class ClassDecl;
62+
class ClangModuleLoader;
6263
class DependentMemberType;
6364
class GenericTypeParamDecl;
6465
class GenericTypeParamType;
@@ -2950,6 +2951,11 @@ class AnyFunctionType : public TypeBase {
29502951

29512952
bool empty() const { return !ClangFunctionType; }
29522953
Uncommon(const clang::Type *type) : ClangFunctionType(type) {}
2954+
2955+
public:
2956+
/// Use the ClangModuleLoader to print the Clang type as a string.
2957+
void printClangFunctionType(ClangModuleLoader *cml,
2958+
llvm::raw_ostream &os);
29532959
};
29542960

29552961
private:

include/swift/ClangImporter/ClangImporter.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,8 @@ class ClangImporter final : public ClangModuleLoader {
420420

421421
const clang::Type *parseClangFunctionType(StringRef type,
422422
SourceLoc loc) const override;
423+
void printClangType(const clang::Type *type,
424+
llvm::raw_ostream &os) const override;
423425
};
424426

425427
ImportDecl *createImportDecl(ASTContext &Ctx, DeclContext *DC, ClangNode ClangN,

include/swift/Frontend/ModuleInterfaceSupport.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ struct ModuleInterfaceOptions {
3131
/// interface, or should we fully-qualify them?
3232
bool PreserveTypesAsWritten = false;
3333

34+
/// Should we emit the cType when printing @convention(c) or no?
35+
/// FIXME: [clang-function-type-serialization] This check should go away.
36+
bool PrintFullConvention = false;
37+
3438
/// Copy of all the command-line flags passed at .swiftinterface
3539
/// generation time, re-applied to CompilerInvocation when reading
3640
/// back .swiftinterface and reconstructing .swiftmodule.

include/swift/Option/FrontendOptions.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,11 @@ def module_interface_preserve_types_as_written :
602602
HelpText<"When emitting a module interface, preserve types as they were "
603603
"written in the source">;
604604

605+
def experimental_print_full_convention :
606+
Flag<["-"], "experimental-print-full-convention">,
607+
HelpText<"When emitting a module interface, emit additional @convention "
608+
"arguments, regardless of whether they were written in the source">;
609+
605610
def prebuilt_module_cache_path :
606611
Separate<["-"], "prebuilt-module-cache-path">,
607612
HelpText<"Directory of prebuilt modules for loading module interfaces">;

lib/AST/ASTPrinter.cpp

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "swift/AST/ASTMangler.h"
2020
#include "swift/AST/ASTVisitor.h"
2121
#include "swift/AST/Attr.h"
22+
#include "swift/AST/ClangModuleLoader.h"
2223
#include "swift/AST/Comment.h"
2324
#include "swift/AST/Decl.h"
2425
#include "swift/AST/Expr.h"
@@ -98,7 +99,8 @@ static bool contributesToParentTypeStorage(const AbstractStorageDecl *ASD) {
9899
return !ND->isResilient() && ASD->hasStorage() && !ASD->isStatic();
99100
}
100101

101-
PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr) {
102+
PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr,
103+
bool printFullConvention) {
102104
PrintOptions result;
103105
result.PrintLongAttrsOnSeparateLines = true;
104106
result.TypeDefinitions = true;
@@ -115,6 +117,9 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(bool preferTypeRepr) {
115117
result.OpaqueReturnTypePrinting =
116118
OpaqueReturnTypePrintingMode::StableReference;
117119
result.PreferTypeRepr = preferTypeRepr;
120+
if (printFullConvention)
121+
result.PrintFunctionRepresentationAttrs =
122+
PrintOptions::FunctionRepresentationMode::Full;
118123

119124
// We should print __consuming, __owned, etc for the module interface file.
120125
result.SkipUnderscoredKeywords = false;
@@ -321,6 +326,14 @@ void ASTPrinter::callPrintDeclPre(const Decl *D,
321326
printDeclPre(D, Bracket);
322327
}
323328

329+
ASTPrinter &ASTPrinter::operator<<(QuotedString s) {
330+
llvm::SmallString<32> Str;
331+
llvm::raw_svector_ostream OS(Str);
332+
OS << s;
333+
printTextImpl(OS.str());
334+
return *this;
335+
}
336+
324337
ASTPrinter &ASTPrinter::operator<<(unsigned long long N) {
325338
llvm::SmallString<32> Str;
326339
llvm::raw_svector_ostream OS(Str);
@@ -3462,6 +3475,15 @@ void Pattern::print(llvm::raw_ostream &OS, const PrintOptions &Options) const {
34623475
// Type Printing
34633476
//===----------------------------------------------------------------------===//
34643477

3478+
template <typename ExtInfo>
3479+
void printCType(ASTContext &Ctx, ASTPrinter &Printer, ExtInfo &info) {
3480+
auto *cml = Ctx.getClangModuleLoader();
3481+
SmallString<64> buf;
3482+
llvm::raw_svector_ostream os(buf);
3483+
info.getUncommonInfo().getValue().printClangFunctionType(cml, os);
3484+
Printer << ", cType: " << QuotedString(os.str());
3485+
}
3486+
34653487
namespace {
34663488
class TypePrinter : public TypeVisitor<TypePrinter> {
34673489
using super = TypeVisitor;
@@ -3824,7 +3846,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
38243846
visit(staticSelfT);
38253847
}
38263848

3827-
void printFunctionExtInfo(AnyFunctionType::ExtInfo info) {
3849+
void printFunctionExtInfo(ASTContext &Ctx, AnyFunctionType::ExtInfo info) {
38283850
if (Options.SkipAttributes)
38293851
return;
38303852

@@ -3837,9 +3859,18 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
38373859
}
38383860
}
38393861

3840-
if (Options.PrintFunctionRepresentationAttrs &&
3841-
!Options.excludeAttrKind(TAK_convention) &&
3842-
info.getSILRepresentation() != SILFunctionType::Representation::Thick) {
3862+
SmallString<64> buf;
3863+
switch (Options.PrintFunctionRepresentationAttrs) {
3864+
case PrintOptions::FunctionRepresentationMode::None:
3865+
return;
3866+
case PrintOptions::FunctionRepresentationMode::Full:
3867+
case PrintOptions::FunctionRepresentationMode::NameOnly:
3868+
if (Options.excludeAttrKind(TAK_convention) ||
3869+
info.getSILRepresentation() == SILFunctionType::Representation::Thick)
3870+
return;
3871+
3872+
bool printNameOnly = Options.PrintFunctionRepresentationAttrs ==
3873+
PrintOptions::FunctionRepresentationMode::NameOnly;
38433874
Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute);
38443875
Printer.printAttrName("@convention");
38453876
Printer << "(";
@@ -3855,6 +3886,11 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
38553886
break;
38563887
case SILFunctionType::Representation::CFunctionPointer:
38573888
Printer << "c";
3889+
// FIXME: [clang-function-type-serialization] Once we start serializing
3890+
// Clang function types, we should be able to remove the second check.
3891+
if (printNameOnly || !info.getUncommonInfo().hasValue())
3892+
break;
3893+
printCType(Ctx, Printer, info);
38583894
break;
38593895
case SILFunctionType::Representation::Method:
38603896
Printer << "method";
@@ -3889,7 +3925,8 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
38893925
}
38903926
}
38913927

3892-
if (Options.PrintFunctionRepresentationAttrs &&
3928+
if ((Options.PrintFunctionRepresentationAttrs !=
3929+
PrintOptions::FunctionRepresentationMode::None) &&
38933930
!Options.excludeAttrKind(TAK_convention) &&
38943931
info.getRepresentation() != SILFunctionType::Representation::Thick) {
38953932
Printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute);
@@ -3975,7 +4012,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
39754012
Printer.printStructurePost(PrintStructureKind::FunctionType);
39764013
};
39774014

3978-
printFunctionExtInfo(T->getExtInfo());
4015+
printFunctionExtInfo(T->getASTContext(), T->getExtInfo());
39794016

39804017
// If we're stripping argument labels from types, do it when printing.
39814018
visitAnyFunctionTypeParams(T->getParams(), /*printLabels*/false);
@@ -4012,7 +4049,7 @@ class TypePrinter : public TypeVisitor<TypePrinter> {
40124049
Printer.printStructurePost(PrintStructureKind::FunctionType);
40134050
};
40144051

4015-
printFunctionExtInfo(T->getExtInfo());
4052+
printFunctionExtInfo(T->getASTContext(), T->getExtInfo());
40164053
printGenericSignature(T->getGenericSignature(),
40174054
PrintAST::PrintParams |
40184055
PrintAST::PrintRequirements);

lib/AST/Type.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "swift/AST/Types.h"
1818
#include "ForeignRepresentationInfo.h"
1919
#include "swift/AST/ASTContext.h"
20+
#include "swift/AST/ClangModuleLoader.h"
2021
#include "swift/AST/ExistentialLayout.h"
2122
#include "swift/AST/ReferenceCounting.h"
2223
#include "swift/AST/TypeCheckRequests.h"
@@ -3239,6 +3240,11 @@ Type ProtocolCompositionType::get(const ASTContext &C,
32393240
return build(C, CanTypes, HasExplicitAnyObject);
32403241
}
32413242

3243+
void AnyFunctionType::ExtInfo::Uncommon::printClangFunctionType(
3244+
ClangModuleLoader *cml, llvm::raw_ostream &os) {
3245+
cml->printClangType(ClangFunctionType, os);
3246+
}
3247+
32423248
void
32433249
AnyFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) {
32443250
#ifndef NDEBUG

lib/ClangImporter/ClangImporter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3292,6 +3292,12 @@ ClangImporter::parseClangFunctionType(StringRef typeStr,
32923292
return nullptr;
32933293
}
32943294

3295+
void ClangImporter::printClangType(const clang::Type *type,
3296+
llvm::raw_ostream &os) const {
3297+
auto policy = clang::PrintingPolicy(getClangASTContext().getLangOpts());
3298+
clang::QualType(type, 0).print(os, policy);
3299+
}
3300+
32953301
//===----------------------------------------------------------------------===//
32963302
// ClangModule Implementation
32973303
//===----------------------------------------------------------------------===//

lib/Frontend/CompilerInvocation.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ static void ParseModuleInterfaceArgs(ModuleInterfaceOptions &Opts,
227227

228228
Opts.PreserveTypesAsWritten |=
229229
Args.hasArg(OPT_module_interface_preserve_types_as_written);
230+
Opts.PrintFullConvention |=
231+
Args.hasArg(OPT_experimental_print_full_convention);
230232
}
231233

232234
/// Save a copy of any flags marked as ModuleInterfaceOption, if running

lib/Frontend/ModuleInterfaceSupport.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ bool swift::emitSwiftInterface(raw_ostream &out,
440440
printImports(out, M);
441441

442442
const PrintOptions printOptions = PrintOptions::printSwiftInterfaceFile(
443-
Opts.PreserveTypesAsWritten);
443+
Opts.PreserveTypesAsWritten, Opts.PrintFullConvention);
444444
InheritedProtocolCollector::PerTypeMap inheritedProtocolMap;
445445

446446
SmallVector<Decl *, 16> topLevelDecls;

lib/IDE/CodeCompletionResultBuilder.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,8 @@ class CodeCompletionResultBuilder {
400400
if (auto AFT = Ty->getAs<AnyFunctionType>()) {
401401
// If this is a closure type, add ChunkKind::CallParameterClosureType.
402402
PrintOptions PO;
403-
PO.PrintFunctionRepresentationAttrs = false;
403+
PO.PrintFunctionRepresentationAttrs =
404+
PrintOptions::FunctionRepresentationMode::None;
404405
PO.SkipAttributes = true;
405406
PO.OpaqueReturnTypePrinting =
406407
PrintOptions::OpaqueReturnTypePrintingMode::WithoutOpaqueKeyword;

lib/IDE/IDETypeChecking.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ PrintOptions PrintOptions::printDocInterface() {
8585
PrintOptions::ArgAndParamPrintingMode::BothAlways;
8686
result.PrintDocumentationComments = false;
8787
result.PrintRegularClangComments = false;
88-
result.PrintFunctionRepresentationAttrs = false;
88+
result.PrintFunctionRepresentationAttrs =
89+
PrintOptions::FunctionRepresentationMode::None;
8990
return result;
9091
}
9192

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %target-swift-frontend -typecheck -swift-version 5 -emit-module-interface-path - -sdk %clang-importer-sdk -enable-library-evolution %s -experimental-print-full-convention | tee ~/tmp.si | %FileCheck %s
2+
3+
import ctypes
4+
5+
// CHECK: f1: (@convention(c, cType: "int (*)(int)") (Swift.Int32) -> Swift.Int32)?
6+
public let f1 = getFunctionPointer_()
7+
8+
// CHECK: f2: (@convention(c, cType: "int (*(*)(int (*)(int)))(int)") ((@convention(c, cType: "int (*)(int)") (Swift.Int32) -> Swift.Int32)?) -> (@convention(c, cType: "int (*)(int)") (Swift.Int32) -> Swift.Int32)?)?
9+
public let f2 = getHigherOrderFunctionPointer()
10+
11+
// CHECK: f3: () -> (@convention(c, cType: "Dummy *(*)(Dummy *)") (Swift.UnsafeMutablePointer<ctypes.Dummy>?) -> Swift.UnsafeMutablePointer<ctypes.Dummy>?)?
12+
public let f3 = getFunctionPointer3

test/Inputs/clang-importer-sdk/usr/include/ctypes.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ typedef int (*fptr)(int);
205205
fptr getFunctionPointer(void);
206206
void useFunctionPointer(fptr);
207207

208+
int (*getFunctionPointer_(void))(int);
209+
208210
struct FunctionPointerWrapper {
209211
fptr a;
210212
fptr b;
@@ -214,6 +216,14 @@ typedef void (*fptr2)(int, long, void *);
214216
fptr2 getFunctionPointer2(void);
215217
void useFunctionPointer2(fptr2);
216218

219+
int (*(*getHigherOrderFunctionPointer(void))(int (*)(int)))(int);
220+
221+
typedef struct Dummy {
222+
int x;
223+
} Dummy;
224+
225+
Dummy * (*getFunctionPointer3(void))(Dummy *);
226+
217227
//===---
218228
// Unions
219229
//===---
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %target-swift-frontend -typecheck -swift-version 5 -emit-module-interface-path - -enable-library-evolution %s -experimental-print-full-convention | %FileCheck %s
2+
3+
public func f(
4+
// CHECK: g: @convention(c, cType: "void (*)(void)")
5+
g: @convention(c) () -> (),
6+
7+
// CHECK: h0: @convention(c, cType: "int (*)(long long)")
8+
h0: @convention(c) (Int64) -> Int32,
9+
// CHECK: h1: @convention(c, cType: "int (*)(long long)")
10+
h1: @convention(c, cType: "int (*)(long long)") (Int64) -> Int32,
11+
12+
// CHECK: i0: @convention(c, cType: "int *(*)(long long, int)")
13+
i0: @convention(c) (Int64, Int32) -> Optional<UnsafeMutablePointer<Int32>>,
14+
// CHECK: i1: @convention(c, cType: "int *(*)(long long, int)")
15+
i1: @convention(c, cType: "int *(*)(long long, int)") (Int64, Int32) -> Optional<UnsafeMutablePointer<Int32>>,
16+
17+
// CHECK: p0: @convention(c, cType: "void (*)(void (*)(long))")
18+
// CHECK: @convention(c, cType: "void (*)(long)")
19+
p0: @convention(c) (@convention(c) (Int) -> Void) -> Void,
20+
21+
// CHECK: p1: @convention(c, cType: "void (*)(void (*)(long))")
22+
// CHECK: @convention(c, cType: "void (*)(long)")
23+
p1: @convention(c, cType: "void (*)(void (*)(long))") (@convention(c) (Int) -> Void) -> Void,
24+
25+
// CHECK: p2: @convention(c, cType: "void (*)(void (*)(long))")
26+
// CHECK: @convention(c, cType: "void (*)(long)")
27+
p2: @convention(c) (@convention(c, cType: "void (*)(long)") (Int) -> Void) -> Void,
28+
29+
// CHECK: p3: @convention(c, cType: "void (*)(void (*)(long))")
30+
// CHECK: @convention(c, cType: "void (*)(long)")
31+
p3: @convention(c, cType: "void (*)(void (*)(long))") (@convention(c, cType: "void (*)(long)") (Int) -> Void) -> Void
32+
) {}

0 commit comments

Comments
 (0)