Skip to content

Commit 62fd801

Browse files
committed
[interop] C++ parameter of reference type should be imported as its pointee type in Swift even if parameter's type is type alias
This finally allows std::vector.push_back to be called with the pushed value directly passed into it
1 parent e05daed commit 62fd801

File tree

10 files changed

+92
-21
lines changed

10 files changed

+92
-21
lines changed

include/swift/ClangImporter/ClangImporter.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,14 @@ namespace importer {
588588
/// Returns true if the given module has a 'cplusplus' requirement.
589589
bool requiresCPlusPlus(const clang::Module *module);
590590

591+
/// Returns the pointee type if the given type is a C++ `const`
592+
/// reference type, `None` otherwise.
593+
llvm::Optional<clang::QualType>
594+
getCxxReferencePointeeTypeOrNone(const clang::Type *type);
595+
596+
/// Returns true if the given type is a C++ `const` reference type.
597+
bool isCxxConstReferenceType(const clang::Type *type);
598+
591599
} // namespace importer
592600

593601
struct ClangInvocationFileMapping {

lib/ClangImporter/ClangImporter.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6832,3 +6832,15 @@ bool importer::requiresCPlusPlus(const clang::Module *module) {
68326832
return req.first == "cplusplus";
68336833
});
68346834
}
6835+
6836+
llvm::Optional<clang::QualType>
6837+
importer::getCxxReferencePointeeTypeOrNone(const clang::Type *type) {
6838+
if (type->isReferenceType())
6839+
return type->getPointeeType();
6840+
return {};
6841+
}
6842+
6843+
bool importer::isCxxConstReferenceType(const clang::Type *type) {
6844+
auto pointeeType = getCxxReferencePointeeTypeOrNone(type);
6845+
return pointeeType && pointeeType->isConstQualified();
6846+
}

lib/ClangImporter/ImportType.cpp

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,20 +2356,32 @@ ClangImporter::Implementation::importParameterType(
23562356
dyn_cast<clang::TemplateTypeParmType>(paramTy)) {
23572357
swiftParamTy = findGenericTypeInGenericDecls(
23582358
*this, templateParamType, genericParams, attrs, addImportDiagnosticFn);
2359-
} else if (auto refType = dyn_cast<clang::ReferenceType>(paramTy)) {
2360-
// We don't support reference type to a dependent type, just bail.
2361-
if (refType->getPointeeType()->isDependentType()) {
2362-
return None;
2363-
}
2359+
}
23642360

2365-
// We don't support rvalue reference types, just bail.
2366-
if (refType->isRValueReferenceType()) {
2367-
return None;
2368-
}
2361+
if (!swiftParamTy) {
2362+
// C++ reference types are brought in as direct
2363+
// types most commonly.
2364+
auto refPointeeType =
2365+
importer::getCxxReferencePointeeTypeOrNone(paramTy.getTypePtr());
2366+
if (refPointeeType) {
2367+
// We don't support reference type to a dependent type, just bail.
2368+
if ((*refPointeeType)->isDependentType()) {
2369+
return None;
2370+
}
23692371

2370-
paramTy = refType->getPointeeType();
2371-
if (!paramTy.isConstQualified())
2372-
isInOut = true;
2372+
// We don't support rvalue reference types, just bail.
2373+
if (paramTy->isRValueReferenceType()) {
2374+
// FIXME: add import diagnostic.
2375+
return None;
2376+
}
2377+
2378+
// A C++ parameter of type `const <type> &` or `<type> &` becomes `<type>`
2379+
// or `inout <type>` in Swift. Note that SILGen will use the indirect
2380+
// parameter convention for such a type.
2381+
paramTy = *refPointeeType;
2382+
if (!paramTy.isConstQualified())
2383+
isInOut = true;
2384+
}
23732385
}
23742386

23752387
// Special case for NSDictionary's subscript.

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1420,8 +1420,7 @@ static bool isClangTypeMoreIndirectThanSubstType(TypeConverter &TC,
14201420
// Pass C++ const reference types indirectly. Right now there's no way to
14211421
// express immutable borrowed params, so we have to have this hack.
14221422
// Eventually, we should just express these correctly: rdar://89647503
1423-
if (clangTy->isReferenceType() &&
1424-
clangTy->getPointeeType().isConstQualified())
1423+
if (importer::isCxxConstReferenceType(clangTy))
14251424
return true;
14261425

14271426
return false;
@@ -3109,7 +3108,7 @@ static bool isCFTypedef(const TypeLowering &tl, clang::QualType type) {
31093108
static ParameterConvention getIndirectCParameterConvention(clang::QualType type) {
31103109
// Non-trivial C++ types would be Indirect_Inout (at least in Itanium).
31113110
// A trivial const * parameter in C should be considered @in.
3112-
if (type->isReferenceType() && type->getPointeeType().isConstQualified())
3111+
if (importer::isCxxConstReferenceType(type.getTypePtr()))
31133112
return ParameterConvention::Indirect_In_Guaranteed;
31143113
return ParameterConvention::Indirect_In;
31153114
}

test/Interop/Cxx/reference/Inputs/reference.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,11 @@ auto getFuncRvalueRef() -> int (&&)() { return getStaticInt; }
2020
void takeConstRef(const int &value) {
2121
staticInt = value;
2222
}
23+
24+
void setConstStaticIntRefTypealias(ConstIntRefTypealias ref) {
25+
staticInt = ref;
26+
}
27+
28+
void setStaticIntRefTypealias(IntRefTypealias ref) {
29+
staticInt = ref;
30+
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ void setConstStaticIntRvalueRef(const int &&);
1616
auto getFuncRef() -> int (&)();
1717
auto getFuncRvalueRef() -> int (&&)();
1818

19+
using ConstIntRefTypealias = const int &;
20+
21+
void setConstStaticIntRefTypealias(ConstIntRefTypealias ref);
22+
23+
using IntRefTypealias = int &;
24+
25+
void setStaticIntRefTypealias(IntRefTypealias ref);
26+
1927
template<class T>
2028
struct ClassTemplate {};
2129

test/Interop/Cxx/reference/reference-module-interface.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
// CHECK: func setConstStaticIntRef(_: Int32)
1111
// CHECK: func getFuncRef() -> @convention(c) () -> Int32
1212
// CHECK: func getFuncRvalueRef() -> @convention(c) () -> Int32
13+
// CHECK: func setConstStaticIntRefTypealias(_ ref: Int32)
14+
// CHECK: func setStaticIntRefTypealias(_ ref: inout Int32)
1315
// CHECK: func refToTemplate<T>(_ t: inout T) -> UnsafeMutablePointer<T>
1416
// CHECK: func constRefToTemplate<T>(_ t: T) -> UnsafePointer<T>
1517

test/Interop/Cxx/reference/reference-silgen.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,21 @@ func setCxxConstRef() {
5151
// CHECK: sil hidden @$s4main14setCxxConstRefyyF : $@convention(thin) () -> ()
5252
// CHECK: [[REF:%.*]] = function_ref @{{_Z20setConstStaticIntRefRKi|\?setConstStaticIntRef@@YAXAEBH@Z}} : $@convention(c) (@in_guaranteed Int32) -> ()
5353
// CHECK: apply [[REF]](%{{[0-9]+}}) : $@convention(c) (@in_guaranteed Int32) -> ()
54+
55+
func setCxxConstRefTypealias() {
56+
let val: CInt = 21
57+
setConstStaticIntRefTypealias(val)
58+
}
59+
60+
// CHECK: sil hidden @$s4main23setCxxConstRefTypealiasyyF : $@convention(thin) () -> ()
61+
// CHECK: [[REF:%.*]] = function_ref @{{_Z29setConstStaticIntRefTypealiasRKi|\?setConstStaticIntRefTypealias@@YAXAEBH@Z}} : $@convention(c) (@in_guaranteed Int32) -> ()
62+
// CHECK: apply [[REF]](%{{[0-9]+}}) : $@convention(c) (@in_guaranteed Int32) -> ()
63+
64+
func setStaticIntRefTypealias() {
65+
var val: CInt = 21
66+
setStaticIntRefTypealias(&val)
67+
}
68+
69+
// CHECK: sil hidden @$s4main24setStaticIntRefTypealiasyyF : $@convention(thin) () -> ()
70+
// CHECK: [[REF:%.*]] = function_ref @{{_Z24setStaticIntRefTypealiasRi|\?setStaticIntRefTypealias@@YAXAEAH@Z}} : $@convention(c) (@inout Int32) -> ()
71+
// CHECK: apply [[REF]](%{{[0-9]+}}) : $@convention(c) (@inout Int32) -> ()

test/Interop/Cxx/reference/reference.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,18 @@ ReferenceTestSuite.test("pass-lvalue-reference") {
4242
var val: CInt = 21
4343
setStaticIntRef(&val)
4444
expectEqual(21, getStaticInt())
45+
val = 111
46+
setStaticIntRefTypealias(&val)
47+
expectEqual(getStaticInt(), 111)
4548
}
4649

4750
ReferenceTestSuite.test("pass-const-lvalue-reference") {
4851
expectNotEqual(22, getStaticInt())
4952
let val: CInt = 22
5053
setConstStaticIntRef(val)
5154
expectEqual(22, getStaticInt())
55+
setConstStaticIntRefTypealias(112)
56+
expectEqual(getStaticInt(), 112)
5257
}
5358

5459
ReferenceTestSuite.test("func-reference") {

test/Interop/Cxx/stdlib/use-std-vector.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,17 @@ StdVectorTestSuite.test("init") {
1919

2020
StdVectorTestSuite.test("push back") {
2121
var v = Vector()
22-
var _42: CInt = 42
23-
v.push_back(&_42)
22+
let _42: CInt = 42
23+
v.push_back(_42)
2424
expectEqual(v.size(), 1)
2525
expectFalse(v.empty())
2626
expectEqual(v[0], 42)
2727
}
2828

2929
func fill(vector v: inout Vector) {
30-
var _1: CInt = 1, _2: CInt = 2, _3: CInt = 3
31-
v.push_back(&_1)
32-
v.push_back(&_2)
33-
v.push_back(&_3)
30+
v.push_back(1)
31+
v.push_back(2)
32+
v.push_back(CInt(3))
3433
}
3534

3635
// TODO: in some configurations the stdlib emits a "initializeWithCopy" where the arguments

0 commit comments

Comments
 (0)