Skip to content

Commit 6a6e9b0

Browse files
authored
Merge pull request #42090 from hyp/i/cxxfuncprim
[cxx-interop] Emit C++ inline function thunks that with correct primitive types
2 parents b681b0a + 71d95b8 commit 6a6e9b0

16 files changed

+435
-111
lines changed

lib/PrintAsClang/ClangSyntaxPrinter.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,32 @@ using namespace cxx_synthesis;
1717

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

20+
bool ClangSyntaxPrinter::isClangKeyword(StringRef name) {
21+
static const llvm::DenseSet<StringRef> keywords = [] {
22+
llvm::DenseSet<StringRef> set;
23+
// FIXME: clang::IdentifierInfo /nearly/ has the API we need to do this
24+
// in a more principled way, but not quite.
25+
#define KEYWORD(SPELLING, FLAGS) set.insert(#SPELLING);
26+
#define CXX_KEYWORD_OPERATOR(SPELLING, TOK) set.insert(#SPELLING);
27+
#include "clang/Basic/TokenKinds.def"
28+
return set;
29+
}();
30+
31+
return keywords.contains(name);
32+
}
33+
34+
bool ClangSyntaxPrinter::isClangKeyword(Identifier name) {
35+
if (name.empty())
36+
return false;
37+
return ClangSyntaxPrinter::isClangKeyword(name.str());
38+
}
39+
40+
void ClangSyntaxPrinter::printIdentifier(StringRef name) {
41+
os << name;
42+
if (ClangSyntaxPrinter::isClangKeyword(name))
43+
os << '_';
44+
}
45+
2046
/// Print a C++ namespace declaration with the give name and body.
2147
void ClangSyntaxPrinter::printNamespace(
2248
llvm::function_ref<void(raw_ostream &OS)> namePrinter,

lib/PrintAsClang/ClangSyntaxPrinter.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ class ClangSyntaxPrinter {
3333
public:
3434
ClangSyntaxPrinter(raw_ostream &os) : os(os) {}
3535

36+
/// Print a given identifier. If the identifer conflicts with a keyword, add a
37+
/// trailing underscore.
38+
void printIdentifier(StringRef name);
39+
3640
/// Print a C++ namespace declaration with the give name and body.
3741
void
3842
printNamespace(llvm::function_ref<void(raw_ostream &OS)> namePrinter,
@@ -53,6 +57,10 @@ class ClangSyntaxPrinter {
5357
Optional<OptionalTypeKind> kind,
5458
NullabilityPrintKind printKind = NullabilityPrintKind::After) const;
5559

60+
/// Returns true if \p name matches a keyword in any Clang language mode.
61+
static bool isClangKeyword(StringRef name);
62+
static bool isClangKeyword(Identifier name);
63+
5664
protected:
5765
raw_ostream &os;
5866
};

lib/PrintAsClang/DeclAndTypePrinter.cpp

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -57,33 +57,6 @@ static bool isAnyObjectOrAny(Type type) {
5757
return type->isAnyObject() || type->isAny();
5858
}
5959

60-
/// Returns true if \p name matches a keyword in any Clang language mode.
61-
static bool isClangKeyword(StringRef name) {
62-
static const llvm::DenseSet<StringRef> keywords = []{
63-
llvm::DenseSet<StringRef> set;
64-
// FIXME: clang::IdentifierInfo /nearly/ has the API we need to do this
65-
// in a more principled way, but not quite.
66-
#define KEYWORD(SPELLING, FLAGS) \
67-
set.insert(#SPELLING);
68-
#define CXX_KEYWORD_OPERATOR(SPELLING, TOK) \
69-
set.insert(#SPELLING);
70-
#include "clang/Basic/TokenKinds.def"
71-
return set;
72-
}();
73-
74-
return keywords.contains(name);
75-
}
76-
77-
static bool isClangKeyword(Identifier name) {
78-
if (name.empty())
79-
return false;
80-
return isClangKeyword(name.str());
81-
}
82-
83-
bool DeclAndTypePrinter::isStrClangKeyword(StringRef name) {
84-
return ::isClangKeyword(name);
85-
}
86-
8760
// For a given Decl and Type, if the type is not an optional return
8861
// the type and OTK_None as the optionality. If the type is
8962
// optional, return the underlying object type, and an optionality
@@ -743,8 +716,7 @@ class DeclAndTypePrinter::Implementation
743716
/// Print the core function declaration for a given function with the given
744717
/// name.
745718
void printFunctionDeclAsCFunctionDecl(FuncDecl *FD, StringRef name,
746-
Type resultTy,
747-
bool printEmptyParamNames = false) {
719+
Type resultTy) {
748720
// The result type may be a partial function type we need to close
749721
// up later.
750722
PrintMultiPartType multiPart(*this);
@@ -764,12 +736,8 @@ class DeclAndTypePrinter::Implementation
764736
Type objTy;
765737
std::tie(objTy, kind) =
766738
getObjectTypeAndOptionality(param, param->getInterfaceType());
767-
std::string paramName =
768-
param->getName().empty() ? "" : param->getName().str().str();
769-
if (printEmptyParamNames && paramName.empty()) {
770-
llvm::raw_string_ostream os(paramName);
771-
os << "_" << index;
772-
}
739+
StringRef paramName =
740+
param->getName().empty() ? "" : param->getName().str();
773741
print(objTy, kind, paramName, IsFunctionParam);
774742
++index;
775743
});
@@ -858,8 +826,9 @@ class DeclAndTypePrinter::Implementation
858826
os << "SWIFT_EXTERN ";
859827

860828
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.typeMapping);
861-
funcPrinter.printFunctionDeclAsCFunctionDecl(FD, funcABI.getSymbolName(),
862-
resultTy);
829+
funcPrinter.printFunctionSignature(
830+
FD, funcABI.getSymbolName(), resultTy,
831+
DeclAndTypeClangFunctionPrinter::FunctionSignatureKind::CFunctionProto);
863832
// Swift functions can't throw exceptions, we can only
864833
// throw them from C++ when emitting C++ inline thunks for the Swift
865834
// functions.
@@ -895,9 +864,10 @@ class DeclAndTypePrinter::Implementation
895864
getForeignResultType(FD, funcTy, asyncConvention, errorConvention);
896865

897866
os << "inline ";
898-
printFunctionDeclAsCFunctionDecl(FD,
899-
FD->getName().getBaseIdentifier().get(),
900-
resultTy, /*printEmptyParamNames=*/true);
867+
DeclAndTypeClangFunctionPrinter funcPrinter(os, owningPrinter.typeMapping);
868+
funcPrinter.printFunctionSignature(
869+
FD, FD->getName().getBaseIdentifier().get(), resultTy,
870+
DeclAndTypeClangFunctionPrinter::FunctionSignatureKind::CxxInlineThunk);
901871
// FIXME: Support throwing exceptions for Swift errors.
902872
os << " noexcept";
903873
printFunctionClangAttributes(FD, funcTy);
@@ -2025,7 +1995,7 @@ class DeclAndTypePrinter::Implementation
20251995
/// visitPart().
20261996
public:
20271997
void print(Type ty, Optional<OptionalTypeKind> optionalKind,
2028-
std::string name = "",
1998+
StringRef name = "",
20291999
IsFunctionParam_t isFuncParam = IsNotFunctionParam) {
20302000
PrettyStackTraceType trace(getASTContext(), "printing", ty);
20312001

lib/PrintAsClang/DeclAndTypePrinter.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,6 @@ class DeclAndTypePrinter {
9292

9393
static std::pair<Type, OptionalTypeKind>
9494
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);
9895
};
9996

10097
} // end namespace swift

lib/PrintAsClang/PrimitiveTypeMapping.cpp

Lines changed: 38 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,20 @@ void PrimitiveTypeMapping::initialize(ASTContext &ctx) {
2424
mappedTypeNames[{ctx.StdlibModuleName, ctx.getIdentifier(#SWIFT_NAME)}] = { \
2525
CLANG_REPR, \
2626
Optional<StringRef>(CLANG_REPR), \
27+
Optional<StringRef>(CLANG_REPR), \
2728
NEEDS_NULLABILITY \
2829
}
2930
#define MAP_C(SWIFT_NAME, OBJC_REPR, C_REPR, NEEDS_NULLABILITY) \
3031
mappedTypeNames[{ctx.StdlibModuleName, ctx.getIdentifier(#SWIFT_NAME)}] = { \
31-
OBJC_REPR, Optional<StringRef>(C_REPR), NEEDS_NULLABILITY}
32+
OBJC_REPR, \
33+
Optional<StringRef>(C_REPR), \
34+
Optional<StringRef>(C_REPR), \
35+
NEEDS_NULLABILITY \
36+
}
37+
#define MAP_CXX(SWIFT_NAME, OBJC_REPR, C_REPR, CXX_REPR, NEEDS_NULLABILITY) \
38+
mappedTypeNames[{ctx.StdlibModuleName, ctx.getIdentifier(#SWIFT_NAME)}] = { \
39+
OBJC_REPR, Optional<StringRef>(C_REPR), Optional<StringRef>(CXX_REPR), \
40+
NEEDS_NULLABILITY}
3241

3342
MAP(CBool, "bool", false);
3443

@@ -66,8 +75,8 @@ void PrimitiveTypeMapping::initialize(ASTContext &ctx) {
6675
MAP(Float32, "float", false);
6776
MAP(Float64, "double", false);
6877

69-
MAP_C(Int, "NSInteger", "ptrdiff_t", false);
70-
MAP_C(UInt, "NSUInteger", "size_t", false);
78+
MAP_CXX(Int, "NSInteger", "ptrdiff_t", "swift::Int", false);
79+
MAP_CXX(UInt, "NSUInteger", "size_t", "swift::UInt", false);
7180
MAP_C(Bool, "BOOL", "bool", false);
7281

7382
MAP(OpaquePointer, "void *", true);
@@ -76,40 +85,40 @@ void PrimitiveTypeMapping::initialize(ASTContext &ctx) {
7685

7786
Identifier ID_ObjectiveC = ctx.Id_ObjectiveC;
7887
mappedTypeNames[{ID_ObjectiveC, ctx.getIdentifier("ObjCBool")}] = {
79-
"BOOL", None, false};
88+
"BOOL", None, None, false};
8089
mappedTypeNames[{ID_ObjectiveC, ctx.getIdentifier("Selector")}] = {
81-
"SEL", None, true};
90+
"SEL", None, None, true};
8291
mappedTypeNames[{ID_ObjectiveC, ctx.getIdentifier(ctx.getSwiftName(
8392
KnownFoundationEntity::NSZone))}] = {
84-
"struct _NSZone *", None, true};
93+
"struct _NSZone *", None, None, true};
8594

8695
mappedTypeNames[{ctx.Id_Darwin, ctx.getIdentifier("DarwinBoolean")}] = {
87-
"Boolean", None, false};
96+
"Boolean", None, None, false};
8897

8998
mappedTypeNames[{ctx.Id_CoreGraphics, ctx.Id_CGFloat}] = {"CGFloat", None,
90-
false};
99+
None, false};
91100

92101
mappedTypeNames[{ctx.Id_CoreFoundation, ctx.Id_CGFloat}] = {"CGFloat", None,
93-
false};
102+
None, false};
94103

95104
// Use typedefs we set up for SIMD vector types.
96105
#define MAP_SIMD_TYPE(BASENAME, _, __) \
106+
StringRef simd2##BASENAME = "swift_" #BASENAME "2"; \
97107
mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "2")}] = { \
98-
"swift_" #BASENAME "2", Optional<StringRef>("swift_" #BASENAME "2"), \
99-
false}; \
108+
simd2##BASENAME, simd2##BASENAME, simd2##BASENAME, false}; \
109+
StringRef simd3##BASENAME = "swift_" #BASENAME "3"; \
100110
mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "3")}] = { \
101-
"swift_" #BASENAME "3", Optional<StringRef>("swift_" #BASENAME "3"), \
102-
false}; \
111+
simd3##BASENAME, simd3##BASENAME, simd3##BASENAME, false}; \
112+
StringRef simd4##BASENAME = "swift_" #BASENAME "4"; \
103113
mappedTypeNames[{ctx.Id_simd, ctx.getIdentifier(#BASENAME "4")}] = { \
104-
"swift_" #BASENAME "4", Optional<StringRef>("swift_" #BASENAME "4"), \
105-
false};
114+
simd4##BASENAME, simd4##BASENAME, simd4##BASENAME, false};
106115
#include "swift/ClangImporter/SIMDMappedTypes.def"
107116
static_assert(SWIFT_MAX_IMPORTED_SIMD_ELEMENTS == 4,
108117
"must add or remove special name mappings if max number of "
109118
"SIMD elements is changed");
110119
}
111120

112-
PrimitiveTypeMapping::ClangTypeInfo *
121+
PrimitiveTypeMapping::FullClangTypeInfo *
113122
PrimitiveTypeMapping::getMappedTypeInfoOrNull(const TypeDecl *typeDecl) {
114123
if (mappedTypeNames.empty())
115124
initialize(typeDecl->getASTContext());
@@ -122,18 +131,27 @@ PrimitiveTypeMapping::getMappedTypeInfoOrNull(const TypeDecl *typeDecl) {
122131
return &iter->second;
123132
}
124133

125-
Optional<PrimitiveTypeMapping::ObjCClangTypeInfo>
134+
Optional<PrimitiveTypeMapping::ClangTypeInfo>
126135
PrimitiveTypeMapping::getKnownObjCTypeInfo(const TypeDecl *typeDecl) {
127136
if (auto *typeInfo = getMappedTypeInfoOrNull(typeDecl))
128-
return ObjCClangTypeInfo{typeInfo->objcName, typeInfo->canBeNullable};
137+
return ClangTypeInfo{typeInfo->objcName, typeInfo->canBeNullable};
129138
return None;
130139
}
131140

132-
Optional<PrimitiveTypeMapping::CClangTypeInfo>
141+
Optional<PrimitiveTypeMapping::ClangTypeInfo>
133142
PrimitiveTypeMapping::getKnownCTypeInfo(const TypeDecl *typeDecl) {
134143
if (auto *typeInfo = getMappedTypeInfoOrNull(typeDecl)) {
135144
if (typeInfo->cName)
136-
return CClangTypeInfo{*typeInfo->cName, typeInfo->canBeNullable};
145+
return ClangTypeInfo{*typeInfo->cName, typeInfo->canBeNullable};
146+
}
147+
return None;
148+
}
149+
150+
Optional<PrimitiveTypeMapping::ClangTypeInfo>
151+
PrimitiveTypeMapping::getKnownCxxTypeInfo(const TypeDecl *typeDecl) {
152+
if (auto *typeInfo = getMappedTypeInfoOrNull(typeDecl)) {
153+
if (typeInfo->cxxName)
154+
return ClangTypeInfo{*typeInfo->cxxName, typeInfo->canBeNullable};
137155
}
138156
return None;
139157
}

lib/PrintAsClang/PrimitiveTypeMapping.h

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,44 +30,45 @@ class TypeDecl;
3030
/// but to something like `intptr_t` or `swift::Int` for C and C++ declarations.
3131
class PrimitiveTypeMapping {
3232
public:
33-
struct ObjCClangTypeInfo {
33+
struct ClangTypeInfo {
3434
StringRef name;
3535
bool canBeNullable;
3636
};
3737

3838
/// Returns the Objective-C type name and nullability for the given Swift
3939
/// primitive type declaration, or \c None if no such type name exists.
40-
Optional<ObjCClangTypeInfo> getKnownObjCTypeInfo(const TypeDecl *typeDecl);
41-
42-
struct CClangTypeInfo {
43-
StringRef name;
44-
bool canBeNullable;
45-
};
40+
Optional<ClangTypeInfo> getKnownObjCTypeInfo(const TypeDecl *typeDecl);
4641

4742
/// Returns the C type name and nullability for the given Swift
4843
/// primitive type declaration, or \c None if no such type name exists.
49-
Optional<CClangTypeInfo> getKnownCTypeInfo(const TypeDecl *typeDecl);
44+
Optional<ClangTypeInfo> getKnownCTypeInfo(const TypeDecl *typeDecl);
45+
46+
/// Returns the C++ type name and nullability for the given Swift
47+
/// primitive type declaration, or \c None if no such type name exists.
48+
Optional<ClangTypeInfo> getKnownCxxTypeInfo(const TypeDecl *typeDecl);
5049

5150
private:
5251
void initialize(ASTContext &ctx);
5352

54-
struct ClangTypeInfo {
53+
struct FullClangTypeInfo {
5554
// The Objective-C name of the Swift type.
5655
StringRef objcName;
5756
// The C name of the Swift type.
5857
Optional<StringRef> cName;
58+
// The C++ name of the Swift type.
59+
Optional<StringRef> cxxName;
5960
bool canBeNullable;
6061
};
6162

62-
ClangTypeInfo *getMappedTypeInfoOrNull(const TypeDecl *typeDecl);
63+
FullClangTypeInfo *getMappedTypeInfoOrNull(const TypeDecl *typeDecl);
6364

6465
/// A map from {Module, TypeName} pairs to {C name, C nullability} pairs.
6566
///
6667
/// This is populated on first use with a list of known Swift types that are
6768
/// translated directly by the ObjC printer instead of structurally, allowing
6869
/// it to do things like map 'Int' to 'NSInteger' and 'Float' to 'float'.
6970
/// In some sense it's the reverse of the ClangImporter's MappedTypes.def.
70-
llvm::DenseMap<std::pair<Identifier, Identifier>, ClangTypeInfo>
71+
llvm::DenseMap<std::pair<Identifier, Identifier>, FullClangTypeInfo>
7172
mappedTypeNames;
7273
};
7374

lib/PrintAsClang/PrintAsClang.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,15 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx,
304304
emitCxxConditional(
305305
out, [&] { emitMacro("SWIFT_NOEXCEPT", "noexcept"); },
306306
[&] { emitMacro("SWIFT_NOEXCEPT"); });
307+
emitCxxConditional(out, [&] {
308+
out << "#if !defined(SWIFT_CXX_INT_DEFINED)\n";
309+
out << "#define SWIFT_CXX_INT_DEFINED\n";
310+
out << "namespace swift {\n";
311+
out << "using Int = ptrdiff_t;\n";
312+
out << "using UInt = size_t;\n";
313+
out << "}\n";
314+
out << "#endif\n";
315+
});
307316
static_assert(SWIFT_MAX_IMPORTED_SIMD_ELEMENTS == 4,
308317
"need to add SIMD typedefs here if max elements is increased");
309318
}

0 commit comments

Comments
 (0)