Skip to content

Commit 288c238

Browse files
committed
[cxx-interop] Ban ObjCBool from being substituted into C++ templates
This fixes a compiler crash when calling a templated C++ function with a parameter of type `ObjCBool` from Swift. The compiler now emits an error for this. Previously the following would happen: 1. Swift starts to emit SILGen for a call expression `takeTAsConstRef(ObjCBool(true))`. 2. `takeTAsConstRef` is a templated C++ function, so Swift asks Clang to instantiate a `takeTAsConstRef` with a built-in Obj-C boolean type. 3. Swift gets an instantiated function template back that looks like this: `void takeTAsConstRef(_Bool t) { ... }`. 4. Swift's ClangImporter begins to import that instantiated function. 5. Since the parameter type is not spelled as `BOOL`, the parameter is not imported as `ObjCBool`. Instead, it's imported as regular Swift `Bool`. 6. Swift realizes that the types don't match (`ObjCBool` vs `Bool`), tries to apply any of the known implicit conversions, fails to do so, crashes. rdar://130424969 (cherry picked from commit fe5b009)
1 parent 907bb90 commit 288c238

File tree

3 files changed

+28
-0
lines changed

3 files changed

+28
-0
lines changed

lib/AST/ClangTypeConverter.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,19 @@ ClangTypeConverter::getClangTemplateArguments(
896896
}
897897

898898
auto replacement = genericArgs[templateParam->getIndex()];
899+
900+
// Ban ObjCBool type from being substituted into C++ templates.
901+
if (auto nominal = replacement->getAs<NominalType>()) {
902+
if (auto nominalDecl = nominal->getDecl()) {
903+
if (nominalDecl->getName().is("ObjCBool") &&
904+
nominalDecl->getModuleContext()->getName() ==
905+
nominalDecl->getASTContext().Id_ObjectiveC) {
906+
failedTypes.push_back(replacement);
907+
continue;
908+
}
909+
}
910+
}
911+
899912
auto qualType = convert(replacement);
900913
if (qualType.isNull()) {
901914
failedTypes.push_back(replacement);

test/Interop/Cxx/templates/Inputs/function-templates.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ template <class T> struct Dep { using TT = T; };
7171

7272
template <class T> void useDependentType(typename Dep<T>::TT) {}
7373

74+
template <class T> void takesValue(T value) { }
75+
7476
template <class T> void lvalueReference(T &ref) { ref = 42; }
7577
template <class T> void lvalueReferenceZero(T &ref) { ref = 0; }
7678

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: not %target-swift-frontend -typecheck %s -I %S/Inputs -enable-experimental-cxx-interop 2>&1 | %FileCheck %s
2+
3+
// REQUIRES: objc_interop
4+
5+
import FunctionTemplates
6+
import ObjectiveC
7+
8+
// Verify that ObjCBool type is banned from C++ template parameters.
9+
10+
takesValue(ObjCBool(true))
11+
// CHECK: error: could not generate C++ types from the generic Swift types provided; the following Swift type(s) provided to 'takesValue' could not be converted: ObjCBool
12+
constLvalueReference(ObjCBool(true))
13+
// CHECK: error: could not generate C++ types from the generic Swift types provided; the following Swift type(s) provided to 'constLvalueReference' could not be converted: ObjCBool

0 commit comments

Comments
 (0)