Skip to content

Commit 94fa8a4

Browse files
committed
[cxx-interop] Do not crash when passing Bool as const T& parameter
The type bridging logic assumed that if a value of type `Swift.Bool` is passed to a Clang function as an argument, then the type of the parameter must be a Clang built-in type (usually `_Bool`). This is not always correct. For instance, the type might be a templated const reference. rdar://125508505 (cherry picked from commit 5b5ffde)
1 parent f39c433 commit 94fa8a4

File tree

6 files changed

+33
-1
lines changed

6 files changed

+33
-1
lines changed

lib/SIL/IR/Bridging.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ Type TypeConverter::getLoweredCBridgedType(AbstractionPattern pattern,
138138
if (nativeBoolTy && t->isEqual(nativeBoolTy)) {
139139
// If we have a Clang type that was imported as Bool, it had better be
140140
// one of a small set of types.
141-
if (clangTy) {
141+
if (clangTy && clangTy->isBuiltinType()) {
142142
auto builtinTy = clangTy->castAs<clang::BuiltinType>();
143143
if (builtinTy->getKind() == clang::BuiltinType::Bool)
144144
return t;

test/Interop/Cxx/reference/Inputs/reference.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ const ClassTemplate<T> &refToDependent() { return ClassTemplate<T>(); }
3535
void dontImportAtomicRef(_Atomic(int)&) { }
3636

3737
void takeConstRef(const int &);
38+
inline bool takeConstRefBool(const bool &b) { return b; }
39+
inline void takeRefBool(bool &b) { b = true; }
3840

3941
template<class T>
4042
T &refToTemplate(T &t) { return t; }

test/Interop/Cxx/reference/reference.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,17 @@ ReferenceTestSuite.test("pod-struct-const-lvalue-reference") {
7878
expectEqual(getStaticInt(), 78)
7979
}
8080

81+
ReferenceTestSuite.test("const reference to bool") {
82+
expectTrue(takeConstRefBool(true))
83+
expectFalse(takeConstRefBool(false))
84+
}
85+
86+
ReferenceTestSuite.test("reference to bool") {
87+
var b = false
88+
takeRefBool(&b)
89+
expectTrue(b)
90+
}
91+
8192
ReferenceTestSuite.test("reference to template") {
8293
var val: CInt = 53
8394
let ref = refToTemplate(&val)

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,12 @@ template <class T> struct Dep { using TT = T; };
7272
template <class T> void useDependentType(typename Dep<T>::TT) {}
7373

7474
template <class T> void lvalueReference(T &ref) { ref = 42; }
75+
template <class T> void lvalueReferenceZero(T &ref) { ref = 0; }
7576

7677
template <class T> void constLvalueReference(const T &) {}
7778

79+
template <class T> bool constLvalueReferenceToBool(const T &t) { return t; }
80+
7881
template <class T> void forwardingReference(T &&) {}
7982

8083
template <class T> void PointerTemplateParameter(T*){}

test/Interop/Cxx/templates/function-template-typechecker-errors.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ public func callIntegerTemplates() {
1515
hasDefaultedNonTypeTemplateParameter()
1616
}
1717

18+
// CHECK: error: unexpected error produced: cannot pass immutable value as inout argument: literals are not mutable
19+
public func callLvalueRef() {
20+
lvalueReference(true)
21+
}
22+
1823
// Use protocol composition to create a type that we cannot (yet) turn into a clang::QualType.
1924
public protocol A { }
2025
public protocol B { }

test/Interop/Cxx/templates/function-template.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ FunctionTemplateTestSuite.test("lvalueReference<T> where T == Int") {
2828
expectEqual(value, 42)
2929
}
3030

31+
FunctionTemplateTestSuite.test("lvalueReferenceZero<T> where T == Bool") {
32+
var value = true
33+
lvalueReferenceZero(&value)
34+
expectEqual(value, false)
35+
}
36+
37+
FunctionTemplateTestSuite.test("constLvalueReferenceToBool<T> where T == Bool") {
38+
expectTrue(constLvalueReferenceToBool(true))
39+
expectFalse(constLvalueReferenceToBool(false))
40+
}
41+
3142
// TODO: Generics, Any, and Protocols should be tested here but need to be
3243
// better supported in ClangTypeConverter first.
3344

0 commit comments

Comments
 (0)