Skip to content

Commit fbbfb70

Browse files
authored
Merge pull request #41965 from hyp/i/cfuncprim
[interop] generate C interfaces for Swift top-level functions that use primitive types
2 parents cee0b4c + 146f9e8 commit fbbfb70

17 files changed

+627
-128
lines changed

lib/PrintAsClang/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11

22
add_swift_host_library(swiftPrintAsClang STATIC
3-
CxxSynthesis.cpp
3+
ClangSyntaxPrinter.cpp
44
DeclAndTypePrinter.cpp
55
ModuleContentsWriter.cpp
66
PrimitiveTypeMapping.cpp
7-
PrintAsClang.cpp)
7+
PrintAsClang.cpp
8+
PrintClangFunction.cpp)
89
target_link_libraries(swiftPrintAsClang PRIVATE
910
swiftAST
1011
swiftClangImporter

lib/PrintAsClang/CxxSynthesis.cpp renamed to lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- CxxSynthesis.cpp - Rules for synthesizing C++ code -----*- C++ -*-===//
1+
//===--- ClangSyntaxPrinter.cpp - Printer for C and C++ code ----*- C++ -*-===//
22
//
33
// This source file is part of the Swift.org open source project
44
//
@@ -10,15 +10,15 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#include "CxxSynthesis.h"
13+
#include "ClangSyntaxPrinter.h"
1414

1515
using namespace swift;
1616
using namespace cxx_synthesis;
1717

1818
StringRef cxx_synthesis::getCxxImplNamespaceName() { return "_impl"; }
1919

2020
/// Print a C++ namespace declaration with the give name and body.
21-
void CxxPrinter::printNamespace(
21+
void ClangSyntaxPrinter::printNamespace(
2222
llvm::function_ref<void(raw_ostream &OS)> namePrinter,
2323
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const {
2424
os << "namespace ";
@@ -30,8 +30,49 @@ void CxxPrinter::printNamespace(
3030
os << "\n\n";
3131
}
3232

33-
void CxxPrinter::printNamespace(
33+
void ClangSyntaxPrinter::printNamespace(
3434
StringRef name,
3535
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const {
3636
printNamespace([&](raw_ostream &os) { os << name; }, bodyPrinter);
3737
}
38+
39+
void ClangSyntaxPrinter::printNullability(
40+
Optional<OptionalTypeKind> kind, NullabilityPrintKind printKind) const {
41+
if (!kind)
42+
return;
43+
44+
switch (printKind) {
45+
case NullabilityPrintKind::ContextSensitive:
46+
switch (*kind) {
47+
case OTK_None:
48+
os << "nonnull";
49+
break;
50+
case OTK_Optional:
51+
os << "nullable";
52+
break;
53+
case OTK_ImplicitlyUnwrappedOptional:
54+
os << "null_unspecified";
55+
break;
56+
}
57+
break;
58+
case NullabilityPrintKind::After:
59+
os << ' ';
60+
LLVM_FALLTHROUGH;
61+
case NullabilityPrintKind::Before:
62+
switch (*kind) {
63+
case OTK_None:
64+
os << "_Nonnull";
65+
break;
66+
case OTK_Optional:
67+
os << "_Nullable";
68+
break;
69+
case OTK_ImplicitlyUnwrappedOptional:
70+
os << "_Null_unspecified";
71+
break;
72+
}
73+
break;
74+
}
75+
76+
if (printKind != NullabilityPrintKind::After)
77+
os << ' ';
78+
}

lib/PrintAsClang/CxxSynthesis.h renamed to lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- CxxSynthesis.h - Rules for synthesizing C++ code -------*- C++ -*-===//
1+
//===--- ClangSyntaxPrinter.h - Printer for C and C++ code ------*- C++ -*-===//
22
//
33
// This source file is part of the Swift.org open source project
44
//
@@ -10,10 +10,11 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13-
#ifndef SWIFT_PRINTASCLANG_CXXSYNTHESIS_H
14-
#define SWIFT_PRINTASCLANG_CXXSYNTHESIS_H
13+
#ifndef SWIFT_PRINTASCLANG_CLANGSYNTAXPRINTER_H
14+
#define SWIFT_PRINTASCLANG_CLANGSYNTAXPRINTER_H
1515

1616
#include "swift/Basic/LLVM.h"
17+
#include "swift/ClangImporter/ClangImporter.h"
1718
#include "llvm/ADT/StringRef.h"
1819
#include "llvm/Support/raw_ostream.h"
1920

@@ -26,9 +27,11 @@ namespace cxx_synthesis {
2627
/// module in C++.
2728
StringRef getCxxImplNamespaceName();
2829

29-
class CxxPrinter {
30+
} // end namespace cxx_synthesis
31+
32+
class ClangSyntaxPrinter {
3033
public:
31-
CxxPrinter(raw_ostream &os) : os(os) {}
34+
ClangSyntaxPrinter(raw_ostream &os) : os(os) {}
3235

3336
/// Print a C++ namespace declaration with the give name and body.
3437
void
@@ -39,11 +42,21 @@ class CxxPrinter {
3942
printNamespace(StringRef name,
4043
llvm::function_ref<void(raw_ostream &OS)> bodyPrinter) const;
4144

42-
private:
45+
/// Where nullability information should be printed.
46+
enum class NullabilityPrintKind {
47+
Before,
48+
After,
49+
ContextSensitive,
50+
};
51+
52+
void printNullability(
53+
Optional<OptionalTypeKind> kind,
54+
NullabilityPrintKind printKind = NullabilityPrintKind::After) const;
55+
56+
protected:
4357
raw_ostream &os;
4458
};
4559

46-
} // end namespace cxx_synthesis
4760
} // end namespace swift
4861

4962
#endif

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 35 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "DeclAndTypePrinter.h"
14-
#include "CxxSynthesis.h"
14+
#include "ClangSyntaxPrinter.h"
1515
#include "PrimitiveTypeMapping.h"
16+
#include "PrintClangFunction.h"
1617

1718
#include "swift/AST/ASTContext.h"
1819
#include "swift/AST/ASTMangler.h"
@@ -79,6 +80,29 @@ static bool isClangKeyword(Identifier name) {
7980
return isClangKeyword(name.str());
8081
}
8182

83+
bool DeclAndTypePrinter::isStrClangKeyword(StringRef name) {
84+
return ::isClangKeyword(name);
85+
}
86+
87+
// For a given Decl and Type, if the type is not an optional return
88+
// the type and OTK_None as the optionality. If the type is
89+
// optional, return the underlying object type, and an optionality
90+
// that is based on the type but overridden by the return value of
91+
// isImplicitlyUnwrappedOptional().
92+
std::pair<Type, OptionalTypeKind>
93+
DeclAndTypePrinter::getObjectTypeAndOptionality(const ValueDecl *D, Type ty) {
94+
OptionalTypeKind kind;
95+
if (auto objTy = ty->getReferenceStorageReferent()->getOptionalObjectType()) {
96+
kind = OTK_Optional;
97+
if (D->isImplicitlyUnwrappedOptional())
98+
kind = OTK_ImplicitlyUnwrappedOptional;
99+
100+
return {objTy, kind};
101+
}
102+
103+
return {ty, OTK_None};
104+
}
105+
82106
namespace {
83107
/// Whether the type being printed is in function param position.
84108
enum IsFunctionParam_t : bool {
@@ -98,17 +122,14 @@ static bool looksLikeInitMethod(ObjCSelector selector) {
98122
}
99123

100124
class DeclAndTypePrinter::Implementation
101-
: private DeclVisitor<DeclAndTypePrinter::Implementation>,
102-
private TypeVisitor<DeclAndTypePrinter::Implementation, void,
103-
Optional<OptionalTypeKind>>
104-
{
125+
: private DeclVisitor<DeclAndTypePrinter::Implementation>,
126+
private TypeVisitor<DeclAndTypePrinter::Implementation, void,
127+
Optional<OptionalTypeKind>>,
128+
private ClangSyntaxPrinter {
105129
using PrinterImpl = Implementation;
106130
friend ASTVisitor;
107131
friend TypeVisitor;
108132

109-
// The output stream is accessible through 'owningPrinter',
110-
// but it makes the code simpler to have it here too.
111-
raw_ostream &os;
112133
DeclAndTypePrinter &owningPrinter;
113134
OutputLanguageMode outputLang;
114135

@@ -126,7 +147,7 @@ class DeclAndTypePrinter::Implementation
126147
public:
127148
explicit Implementation(raw_ostream &out, DeclAndTypePrinter &owner,
128149
OutputLanguageMode outputLang)
129-
: os(out), owningPrinter(owner), outputLang(outputLang) {}
150+
: ClangSyntaxPrinter(out), owningPrinter(owner), outputLang(outputLang) {}
130151

131152
void print(const Decl *D) {
132153
PrettyStackTraceDecl trace("printing", D);
@@ -285,17 +306,7 @@ class DeclAndTypePrinter::Implementation
285306
// isImplicitlyUnwrappedOptional().
286307
static std::pair<Type, OptionalTypeKind>
287308
getObjectTypeAndOptionality(const ValueDecl *D, Type ty) {
288-
OptionalTypeKind kind;
289-
if (auto objTy =
290-
ty->getReferenceStorageReferent()->getOptionalObjectType()) {
291-
kind = OTK_Optional;
292-
if (D->isImplicitlyUnwrappedOptional())
293-
kind = OTK_ImplicitlyUnwrappedOptional;
294-
295-
return {objTy, kind};
296-
}
297-
298-
return {ty, OTK_None};
309+
return DeclAndTypePrinter::getObjectTypeAndOptionality(D, ty);
299310
}
300311

301312
// Ignore other declarations.
@@ -845,7 +856,10 @@ class DeclAndTypePrinter::Implementation
845856
FuncionSwiftABIInformation funcABI(FD, mangler);
846857

847858
os << "SWIFT_EXTERN ";
848-
printFunctionDeclAsCFunctionDecl(FD, funcABI.getSymbolName(), resultTy);
859+
860+
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.typeMapping);
861+
funcPrinter.printFunctionDeclAsCFunctionDecl(FD, funcABI.getSymbolName(),
862+
resultTy);
849863
// Swift functions can't throw exceptions, we can only
850864
// throw them from C++ when emitting C++ inline thunks for the Swift
851865
// functions.
@@ -1372,55 +1386,6 @@ class DeclAndTypePrinter::Implementation
13721386
TypeVisitor::visit(ty, optionalKind);
13731387
}
13741388

1375-
/// Where nullability information should be printed.
1376-
enum class NullabilityPrintKind {
1377-
Before,
1378-
After,
1379-
ContextSensitive,
1380-
};
1381-
1382-
void printNullability(Optional<OptionalTypeKind> kind,
1383-
NullabilityPrintKind printKind
1384-
= NullabilityPrintKind::After) {
1385-
if (!kind)
1386-
return;
1387-
1388-
switch (printKind) {
1389-
case NullabilityPrintKind::ContextSensitive:
1390-
switch (*kind) {
1391-
case OTK_None:
1392-
os << "nonnull";
1393-
break;
1394-
case OTK_Optional:
1395-
os << "nullable";
1396-
break;
1397-
case OTK_ImplicitlyUnwrappedOptional:
1398-
os << "null_unspecified";
1399-
break;
1400-
}
1401-
break;
1402-
case NullabilityPrintKind::After:
1403-
os << ' ';
1404-
LLVM_FALLTHROUGH;
1405-
case NullabilityPrintKind::Before:
1406-
switch (*kind) {
1407-
case OTK_None:
1408-
os << "_Nonnull";
1409-
break;
1410-
case OTK_Optional:
1411-
os << "_Nullable";
1412-
break;
1413-
case OTK_ImplicitlyUnwrappedOptional:
1414-
os << "_Null_unspecified";
1415-
break;
1416-
}
1417-
break;
1418-
}
1419-
1420-
if (printKind != NullabilityPrintKind::After)
1421-
os << ' ';
1422-
}
1423-
14241389
/// Determine whether this generic Swift nominal type maps to a
14251390
/// generic Objective-C class.
14261391
static bool hasGenericObjCType(const NominalTypeDecl *nominal) {

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ namespace clang {
2626
namespace swift {
2727

2828
class PrimitiveTypeMapping;
29+
class ValueDecl;
2930

3031
/// Responsible for printing a Swift Decl or Type in Objective-C, to be
3132
/// included in a Swift module's ObjC compatibility header.
@@ -88,6 +89,12 @@ class DeclAndTypePrinter {
8889
/// Returns the name of an <os/object.h> type minus the leading "OS_",
8990
/// or an empty string if \p decl is not an <os/object.h> type.
9091
static StringRef maybeGetOSObjectBaseName(const clang::NamedDecl *decl);
92+
93+
static std::pair<Type, OptionalTypeKind>
94+
getObjectTypeAndOptionality(const ValueDecl *D, Type ty);
95+
96+
/// Returns true if \p name matches a keyword in any Clang language mode.
97+
static bool isStrClangKeyword(StringRef name);
9198
};
9299

93100
} // end namespace swift

lib/PrintAsClang/ModuleContentsWriter.cpp

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
#include "ModuleContentsWriter.h"
1414

15-
#include "CxxSynthesis.h"
15+
#include "ClangSyntaxPrinter.h"
1616
#include "DeclAndTypePrinter.h"
1717
#include "OutputLanguageMode.h"
1818
#include "PrimitiveTypeMapping.h"
@@ -642,26 +642,34 @@ swift::printModuleContentsAsObjC(raw_ostream &os,
642642
void swift::printModuleContentsAsCxx(
643643
raw_ostream &os, llvm::SmallPtrSetImpl<ImportModuleTy> &imports,
644644
ModuleDecl &M) {
645-
using cxx_synthesis::CxxPrinter;
645+
std::string moduleContentsBuf;
646+
llvm::raw_string_ostream moduleOS{moduleContentsBuf};
647+
std::string modulePrologueBuf;
648+
llvm::raw_string_ostream prologueOS{modulePrologueBuf};
649+
650+
ModuleWriter(moduleOS, prologueOS, imports, M, getRequiredAccess(M),
651+
OutputLanguageMode::Cxx)
652+
.write();
653+
654+
// FIXME: refactor.
655+
if (!prologueOS.str().empty()) {
656+
os << "#endif\n";
657+
os << "#ifdef __cplusplus\n";
658+
os << "namespace ";
659+
M.ValueDecl::getName().print(os);
660+
os << " {\n";
661+
os << "namespace " << cxx_synthesis::getCxxImplNamespaceName() << " {\n";
662+
os << "#endif\n\n";
663+
664+
os << prologueOS.str();
665+
666+
os << "\n#ifdef __cplusplus\n";
667+
os << "}\n";
668+
os << "}\n";
669+
}
670+
646671
// Construct a C++ namespace for the module.
647-
CxxPrinter(os).printNamespace(
672+
ClangSyntaxPrinter(os).printNamespace(
648673
[&](raw_ostream &os) { M.ValueDecl::getName().print(os); },
649-
[&](raw_ostream &os) {
650-
std::string moduleContentsBuf;
651-
llvm::raw_string_ostream moduleOS{moduleContentsBuf};
652-
std::string modulePrologueBuf;
653-
llvm::raw_string_ostream prologueOS{modulePrologueBuf};
654-
655-
ModuleWriter(moduleOS, prologueOS, imports, M, getRequiredAccess(M),
656-
OutputLanguageMode::Cxx)
657-
.write();
658-
659-
// The module's prologue contains implementation details,
660-
// like extern "C" symbols for the referenced Swift functions.
661-
CxxPrinter(os).printNamespace(
662-
cxx_synthesis::getCxxImplNamespaceName(),
663-
[&](raw_ostream &os) { os << prologueOS.str(); });
664-
665-
os << moduleOS.str();
666-
});
674+
[&](raw_ostream &os) { os << moduleOS.str(); });
667675
}

0 commit comments

Comments
 (0)