Skip to content

Commit cda4dc5

Browse files
Merge pull request #76859 from j-hui/fix-frt-conversion
[cxx-interop] Fix swift::Type to clang::QualType conversion to correctly handle foreign reference types
2 parents fc7068e + ec506f8 commit cda4dc5

File tree

5 files changed

+95
-1
lines changed

5 files changed

+95
-1
lines changed

lib/AST/ClangTypeConverter.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,11 @@ clang::QualType ClangTypeConverter::convert(Type type) {
839839
if (auto clangDecl = decl->getClangDecl()) {
840840
auto &ctx = ClangASTContext;
841841
if (auto clangTypeDecl = dyn_cast<clang::TypeDecl>(clangDecl)) {
842-
return ctx.getTypeDeclType(clangTypeDecl).getUnqualifiedType();
842+
auto qualType = ctx.getTypeDeclType(clangTypeDecl);
843+
if (type->isForeignReferenceType()) {
844+
qualType = ctx.getPointerType(qualType);
845+
}
846+
return qualType.getUnqualifiedType();
843847
} else if (auto ifaceDecl = dyn_cast<clang::ObjCInterfaceDecl>(clangDecl)) {
844848
auto clangType = ctx.getObjCInterfaceType(ifaceDecl);
845849
return ctx.getObjCObjectPointerType(clangType);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#pragma once
2+
3+
// A wrapper around C++'s static_cast(), which allows Swift to get around interop's current lack of support for inheritance.
4+
template <class I, class O> O cxxCast(I i) { return static_cast<O>(i); }
5+
6+
// A minimal foreign reference type.
7+
struct
8+
__attribute__((swift_attr("import_reference")))
9+
__attribute__((swift_attr("retain:immortal")))
10+
__attribute__((swift_attr("release:immortal")))
11+
BaseT {
12+
public:
13+
bool isBase;
14+
BaseT() { isBase = true; }
15+
BaseT(const BaseT &) = delete;
16+
static BaseT &getBaseT() { static BaseT singleton; return singleton; }
17+
};
18+
19+
// A foreign reference type that is a subclass of BaseT.
20+
struct
21+
__attribute__((swift_attr("import_reference")))
22+
__attribute__((swift_attr("retain:immortal")))
23+
__attribute__((swift_attr("release:immortal")))
24+
SubT : BaseT {
25+
public:
26+
SubT() { isBase = false; }
27+
SubT(const SubT &) = delete;
28+
static SubT &getSubT() { static SubT singleton; return singleton; }
29+
};

test/Interop/Cxx/foreign-reference/Inputs/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ module Nullable {
1818
requires cplusplus
1919
}
2020

21+
module Inheritance {
22+
header "inheritance.h"
23+
requires cplusplus
24+
}
25+
2126
module WitnessTable {
2227
header "witness-table.h"
2328
requires cplusplus
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %target-typecheck-verify-swift -cxx-interoperability-mode=default -disable-availability-checking -I %S/Inputs
2+
3+
import Inheritance
4+
5+
// A function whose explicit type annotations specializes the cxxCast function.
6+
//
7+
// In Swift, the generic type parameters of cxxCast I and O should be respectively instantiated to SubT and BaseT.
8+
// However, since these are foreign reference types, this instantiates (and calls) cxxCast<SubT *, BaseT *> in C++.
9+
func cast(_ s: SubT) -> BaseT {
10+
return cxxCast(s)
11+
}
12+
13+
let s: SubT = SubT.getSubT()
14+
assert(!s.isBase)
15+
let sc: BaseT = cast(s)
16+
assert(!sc.isBase)
17+
let sx: BaseT = cxxCast(s) // should instantiate I to SubT and O to BaseT
18+
assert(!sc.isBase)
19+
20+
let b: BaseT = BaseT.getBaseT()
21+
assert(b.isBase)
22+
let bc: BaseT = cxxCast(b) // should instantiate I and O both to BaseT
23+
assert(bc.isBase)
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// REQUIRES: executable_test
2+
// RUN: %target-run-simple-swift(-cxx-interoperability-mode=default -Xfrontend -disable-availability-checking -I %S/Inputs)
3+
4+
import StdlibUnittest
5+
import Inheritance
6+
7+
// A function whose explicit type annotations specializes the cxxCast function.
8+
//
9+
// In Swift, the generic type parameters of cxxCast I and O should be respectively instantiated to SubT and BaseT.
10+
// However, since these are foreign reference types, this instantiates (and calls) cxxCast<SubT *, BaseT *> in C++.
11+
func cast(_ s: SubT) -> BaseT {
12+
return cxxCast(s)
13+
}
14+
15+
var TemplatingTestSuite = TestSuite("Foreign references work with templates")
16+
17+
TemplatingTestSuite.test("SubT") {
18+
let s: SubT = SubT.getSubT()
19+
assert(!s.isBase)
20+
let sc: BaseT = cast(s)
21+
assert(!sc.isBase)
22+
let sx: BaseT = cxxCast(s) // should instantiate I to SubT and O to BaseT
23+
assert(!sc.isBase)
24+
}
25+
26+
TemplatingTestSuite.test("BaseT") {
27+
let b: BaseT = BaseT.getBaseT()
28+
assert(b.isBase)
29+
let bc: BaseT = cxxCast(b) // should instantiate I and O both to BaseT
30+
assert(bc.isBase)
31+
}
32+
33+
runAllTests()

0 commit comments

Comments
 (0)