Skip to content

Commit 41c9651

Browse files
authored
Merge pull request #42431 from zoecarver/param-types-use-enum-not-typedef
[cxx-interop] Import enum, not typedef for parameter types.
2 parents 66b341f + e6af2d9 commit 41c9651

File tree

5 files changed

+98
-26
lines changed

5 files changed

+98
-26
lines changed

lib/ClangImporter/ImportType.cpp

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2125,6 +2125,20 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType(
21252125
ImportedType importedType;
21262126
ImportDiagnosticAdder addDiag(*this, clangDecl,
21272127
clangDecl->getSourceRange().getBegin());
2128+
if (auto typedefType = dyn_cast<clang::TypedefType>(clangDecl->getReturnType().getTypePtr())) {
2129+
if (isUnavailableInSwift(typedefType->getDecl())) {
2130+
if (auto clangEnum = findAnonymousEnumForTypedef(SwiftContext, typedefType)) {
2131+
// If this fails, it means that we need a stronger predicate for
2132+
// determining the relationship between an enum and typedef.
2133+
assert(clangEnum.getValue()->getIntegerType()->getCanonicalTypeInternal() ==
2134+
typedefType->getCanonicalTypeInternal());
2135+
if (auto swiftEnum = importDecl(*clangEnum, CurrentVersion)) {
2136+
importedType = {cast<NominalTypeDecl>(swiftEnum)->getDeclaredType(), false};
2137+
}
2138+
}
2139+
}
2140+
}
2141+
21282142
if (auto templateType =
21292143
dyn_cast<clang::TemplateTypeParmType>(clangDecl->getReturnType())) {
21302144
importedType = {findGenericTypeInGenericDecls(
@@ -2150,11 +2164,15 @@ ImportedType ClangImporter::Implementation::importFunctionParamsAndReturnType(
21502164
clangDecl->isOverloadedOperator() ||
21512165
// Dependant types are trivially mapped as Any.
21522166
clangDecl->getReturnType()->isDependentType()) {
2153-
importedType =
2154-
importFunctionReturnType(dc, clangDecl, allowNSUIntegerAsInt);
2167+
// If importedType is already initialized, it means we found the enum that
2168+
// was supposed to be used (instead of the typedef type).
21552169
if (!importedType) {
2156-
addDiag(Diagnostic(diag::return_type_not_imported));
2157-
return {Type(), false};
2170+
importedType =
2171+
importFunctionReturnType(dc, clangDecl, allowNSUIntegerAsInt);
2172+
if (!importedType) {
2173+
addDiag(Diagnostic(diag::return_type_not_imported));
2174+
return {Type(), false};
2175+
}
21582176
}
21592177
}
21602178

@@ -2238,7 +2256,22 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
22382256
Type swiftParamTy;
22392257
bool isParamTypeImplicitlyUnwrapped = false;
22402258
bool isInOut = false;
2241-
if (isa<clang::PointerType>(paramTy) &&
2259+
2260+
// Sometimes we import unavailable typedefs as enums. If that's the case,
2261+
// use the enum, not the typedef here.
2262+
if (auto typedefType = dyn_cast<clang::TypedefType>(paramTy.getTypePtr())) {
2263+
if (isUnavailableInSwift(typedefType->getDecl())) {
2264+
if (auto clangEnum = findAnonymousEnumForTypedef(SwiftContext, typedefType)) {
2265+
// If this fails, it means that we need a stronger predicate for
2266+
// determining the relationship between an enum and typedef.
2267+
assert(clangEnum.getValue()->getIntegerType()->getCanonicalTypeInternal() ==
2268+
typedefType->getCanonicalTypeInternal());
2269+
if (auto swiftEnum = importDecl(*clangEnum, CurrentVersion)) {
2270+
swiftParamTy = cast<NominalTypeDecl>(swiftEnum)->getDeclaredType();
2271+
}
2272+
}
2273+
}
2274+
} else if (isa<clang::PointerType>(paramTy) &&
22422275
isa<clang::TemplateTypeParmType>(paramTy->getPointeeType())) {
22432276
auto pointeeType = paramTy->getPointeeType();
22442277
auto templateParamType = cast<clang::TemplateTypeParmType>(pointeeType);
@@ -2265,20 +2298,21 @@ ParameterList *ClangImporter::Implementation::importFunctionParameterList(
22652298
swiftParamTy =
22662299
findGenericTypeInGenericDecls(*this, templateParamType, genericParams,
22672300
attrs, paramAddDiag);
2268-
} else {
2269-
if (auto refType = dyn_cast<clang::ReferenceType>(paramTy)) {
2270-
// We don't support reference type to a dependent type, just bail.
2271-
if (refType->getPointeeType()->isDependentType()) {
2272-
addImportDiagnostic(
2273-
param, Diagnostic(diag::parameter_type_not_imported, param),
2274-
param->getSourceRange().getBegin());
2275-
return nullptr;
2276-
}
2277-
2278-
paramTy = refType->getPointeeType();
2279-
if (!paramTy.isConstQualified())
2280-
isInOut = true;
2301+
} else if (auto refType = dyn_cast<clang::ReferenceType>(paramTy)) {
2302+
// We don't support reference type to a dependent type, just bail.
2303+
if (refType->getPointeeType()->isDependentType()) {
2304+
addImportDiagnostic(
2305+
param, Diagnostic(diag::parameter_type_not_imported, param),
2306+
param->getSourceRange().getBegin());
2307+
return nullptr;
22812308
}
2309+
2310+
paramTy = refType->getPointeeType();
2311+
if (!paramTy.isConstQualified())
2312+
isInOut = true;
2313+
}
2314+
2315+
if (!swiftParamTy) {
22822316
auto importedType = importType(paramTy, importKind, paramAddDiag,
22832317
allowNSUIntegerAsInt, Bridgeability::Full,
22842318
attrs, OptionalityOfParam);

lib/ClangImporter/ImporterImpl.h

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
#include "swift/ClangImporter/ClangImporter.h"
3434
#include "swift/ClangImporter/ClangModule.h"
3535
#include "clang/AST/ASTContext.h"
36+
#include "clang/AST/Decl.h"
37+
#include "clang/Lex/MacroInfo.h"
38+
#include "clang/Lex/Preprocessor.h"
3639
#include "clang/AST/DeclVisitor.h"
3740
#include "clang/AST/RecursiveASTVisitor.h"
3841
#include "clang/Basic/IdentifierTable.h"
@@ -60,12 +63,8 @@ class SmallBitVector;
6063

6164
namespace clang {
6265
class APValue;
63-
class Decl;
6466
class DeclarationName;
65-
class EnumDecl;
66-
class MacroInfo;
6767
class MangleContext;
68-
class NamedDecl;
6968
class ObjCInterfaceDecl;
7069
class ObjCMethodDecl;
7170
class ObjCPropertyDecl;
@@ -1869,6 +1868,26 @@ static inline Type applyToFunctionType(
18691868
return type;
18701869
}
18711870

1871+
inline Optional<const clang::EnumDecl *> findAnonymousEnumForTypedef(
1872+
const ASTContext &ctx,
1873+
const clang::TypedefType *typedefType) {
1874+
auto *typedefDecl = typedefType->getDecl();
1875+
auto *lookupTable = ctx.getClangModuleLoader()->findLookupTable(typedefDecl->getOwningModule());
1876+
1877+
auto foundDecls = lookupTable->lookup(
1878+
SerializedSwiftName(typedefDecl->getName()), EffectiveClangContext());
1879+
1880+
auto found = llvm::find_if(foundDecls, [](SwiftLookupTable::SingleEntry decl) {
1881+
return decl.is<clang::NamedDecl *>() &&
1882+
isa<clang::EnumDecl>(decl.get<clang::NamedDecl *>());
1883+
});
1884+
1885+
if (found != foundDecls.end())
1886+
return cast<clang::EnumDecl>(found->get<clang::NamedDecl *>());
1887+
1888+
return None;
1889+
}
1890+
18721891
}
18731892
}
18741893

test/Interop/Cxx/enum/Inputs/anonymous-with-swift-name.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,7 @@ typedef CF_OPTIONS(unsigned, CFColorMask) {
1919
kCFColorMaskAll = ~0U
2020
};
2121

22+
inline SOColorMask useSOColorMask(SOColorMask mask) { return mask; }
23+
inline CFColorMask useCFColorMask(CFColorMask mask) { return mask; }
24+
2225
#endif // TEST_INTEROP_CXX_ENUM_INPUTS_ANONYMOUS_WITH_SWIFT_NAME_H

test/Interop/Cxx/enum/anonymous-with-swift-name-module-interface.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,6 @@
5353
// CHECK: @available(swift, obsoleted: 3, renamed: "all")
5454
// CHECK: static var All: CFColorMask { get }
5555
// CHECK: }
56+
57+
// CHECK: func useSOColorMask(_ mask: SOColorMask) -> SOColorMask
58+
// CHECK: func useCFColorMask(_ mask: CFColorMask) -> CFColorMask

test/Interop/Cxx/enum/anonymous-with-swift-name.swift

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,28 @@ AnonymousEnumsTestSuite.test("SOME_OPTIONS") {
2020
}
2121

2222
AnonymousEnumsTestSuite.test("CF_OPTIONS") {
23-
let red: SOColorMask = .red
24-
let green = SOColorMask.green
25-
let blue = .blue as SOColorMask
26-
let all: SOColorMask = .all
23+
let red: CFColorMask = .red
24+
let green = CFColorMask.green
25+
let blue = .blue as CFColorMask
26+
let all: CFColorMask = .all
2727

2828
expectEqual(red.rawValue, 2)
2929
expectEqual(green.rawValue, 4)
3030
expectEqual(blue.rawValue, 8)
3131
expectEqual(all.rawValue, ~CUnsignedInt(0))
3232
}
3333

34+
AnonymousEnumsTestSuite.test("Parameter types") {
35+
let red: CFColorMask = .red
36+
let green = CFColorMask.green
37+
38+
let blue = useSOColorMask(.blue)
39+
let all = useSOColorMask(.all)
40+
41+
expectEqual(red, useCFColorMask(.red))
42+
expectEqual(green, useCFColorMask(.green))
43+
expectEqual(blue, .blue)
44+
expectEqual(all, .all)
45+
}
46+
3447
runAllTests()

0 commit comments

Comments
 (0)