Skip to content

Commit 30b5fd5

Browse files
authored
[CxxInterop] Import C++ references. (#31702)
1 parent d9c3a84 commit 30b5fd5

File tree

12 files changed

+364
-25
lines changed

12 files changed

+364
-25
lines changed

include/swift/AST/Types.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2696,10 +2696,10 @@ enum class FunctionTypeRepresentation : uint8_t {
26962696
/// A "thin" function that needs no context.
26972697
Thin,
26982698

2699-
/// A C function pointer, which is thin and also uses the C calling
2700-
/// convention.
2699+
/// A C function pointer (or reference), which is thin and also uses the C
2700+
/// calling convention.
27012701
CFunctionPointer,
2702-
2702+
27032703
/// The value of the greatest AST function representation.
27042704
Last = CFunctionPointer,
27052705
};
@@ -2980,8 +2980,8 @@ class AnyFunctionType : public TypeBase {
29802980
// We preserve a full clang::Type *, not a clang::FunctionType * as:
29812981
// 1. We need to keep sugar in case we need to present an error to the user.
29822982
// 2. The actual type being stored is [ignoring sugar] either a
2983-
// clang::PointerType or a clang::BlockPointerType which points to a
2984-
// clang::FunctionType.
2983+
// clang::PointerType, a clang::BlockPointerType, or a
2984+
// clang::ReferenceType which points to a clang::FunctionType.
29852985
const clang::Type *ClangFunctionType;
29862986

29872987
bool empty() const { return !ClangFunctionType; }

lib/AST/Type.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3376,7 +3376,8 @@ void AnyFunctionType::ExtInfo::Uncommon::printClangFunctionType(
33763376
void
33773377
AnyFunctionType::ExtInfo::assertIsFunctionType(const clang::Type *type) {
33783378
#ifndef NDEBUG
3379-
if (!(type->isFunctionPointerType() || type->isBlockPointerType())) {
3379+
if (!(type->isFunctionPointerType() || type->isBlockPointerType() ||
3380+
type->isFunctionReferenceType())) {
33803381
SmallString<256> buf;
33813382
llvm::raw_svector_ostream os(buf);
33823383
os << "Expected a Clang function type wrapped in a pointer type or "

lib/ClangImporter/ImportType.cpp

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,30 @@ namespace {
159159
explicit operator bool() const { return (bool) AbstractType; }
160160
};
161161

162+
static ImportResult importFunctionPointerLikeType(const clang::Type &type,
163+
const Type &pointeeType) {
164+
auto funcTy = pointeeType->castTo<FunctionType>();
165+
return {FunctionType::get(
166+
funcTy->getParams(), funcTy->getResult(),
167+
funcTy->getExtInfo()
168+
.withRepresentation(
169+
AnyFunctionType::Representation::CFunctionPointer)
170+
.withClangFunctionType(&type)),
171+
type.isReferenceType() ? ImportHint::None
172+
: ImportHint::CFunctionPointer};
173+
}
174+
175+
static ImportResult importOverAlignedFunctionPointerLikeType(
176+
const clang::Type &type, ClangImporter::Implementation &Impl) {
177+
auto opaquePointer = Impl.SwiftContext.getOpaquePointerDecl();
178+
if (!opaquePointer) {
179+
return Type();
180+
}
181+
return {opaquePointer->getDeclaredType(),
182+
type.isReferenceType() ? ImportHint::None
183+
: ImportHint::OtherPointer};
184+
}
185+
162186
class SwiftTypeConverter :
163187
public clang::TypeVisitor<SwiftTypeConverter, ImportResult>
164188
{
@@ -406,23 +430,11 @@ namespace {
406430
// alignment is greater than the maximum Swift alignment, import as
407431
// OpaquePointer.
408432
if (!pointeeType || Impl.isOverAligned(pointeeQualType)) {
409-
auto opaquePointer = Impl.SwiftContext.getOpaquePointerDecl();
410-
if (!opaquePointer)
411-
return Type();
412-
return {opaquePointer->getDeclaredType(),
413-
ImportHint::OtherPointer};
433+
return importOverAlignedFunctionPointerLikeType(*type, Impl);
414434
}
415-
435+
416436
if (pointeeQualType->isFunctionType()) {
417-
auto funcTy = pointeeType->castTo<FunctionType>();
418-
return {
419-
FunctionType::get(funcTy->getParams(), funcTy->getResult(),
420-
funcTy->getExtInfo()
421-
.withRepresentation(
422-
AnyFunctionType::Representation::CFunctionPointer)
423-
.withClangFunctionType(type)),
424-
ImportHint::CFunctionPointer
425-
};
437+
return importFunctionPointerLikeType(*type, pointeeType);
426438
}
427439

428440
PointerTypeKind pointerKind;
@@ -472,7 +484,29 @@ namespace {
472484
}
473485

474486
ImportResult VisitReferenceType(const clang::ReferenceType *type) {
475-
return Type();
487+
auto pointeeQualType = type->getPointeeType();
488+
auto quals = pointeeQualType.getQualifiers();
489+
Type pointeeType =
490+
Impl.importTypeIgnoreIUO(pointeeQualType, ImportTypeKind::Value,
491+
AllowNSUIntegerAsInt, Bridgeability::None);
492+
493+
if (pointeeQualType->isFunctionType()) {
494+
return importFunctionPointerLikeType(*type, pointeeType);
495+
}
496+
497+
if (Impl.isOverAligned(pointeeQualType)) {
498+
return importOverAlignedFunctionPointerLikeType(*type, Impl);
499+
}
500+
501+
PointerTypeKind pointerKind;
502+
if (quals.hasConst()) {
503+
pointerKind = PTK_UnsafePointer;
504+
} else {
505+
pointerKind = PTK_UnsafeMutablePointer;
506+
}
507+
508+
return {pointeeType->wrapInPointer(pointerKind),
509+
ImportHint::None};
476510
}
477511

478512
ImportResult VisitMemberPointer(const clang::MemberPointerType *type) {

lib/ClangImporter/ImporterImpl.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,9 +135,10 @@ enum class ImportTypeKind {
135135

136136
/// Import the type of a function parameter.
137137
///
138-
/// This provides special treatment for C++ references (which become
139-
/// [inout] parameters) and C pointers (which become magic [inout]-able types),
140-
/// among other things, and enables the conversion of bridged types.
138+
/// Special handling:
139+
/// * C and C++ pointers become `UnsafePointer?` or `UnsafeMutablePointer?`
140+
/// * C++ references become `UnsafePointer` or `UnsafeMutablePointer`
141+
/// * Bridging that requires type conversions is allowed.
141142
/// Parameters are always considered CF-audited.
142143
Parameter,
143144

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,8 @@ getClangFunctionType(const clang::Type *clangType) {
319319
clangType = ptrTy->getPointeeType().getTypePtr();
320320
} else if (auto blockTy = clangType->getAs<clang::BlockPointerType>()) {
321321
clangType = blockTy->getPointeeType().getTypePtr();
322+
} else if (auto refTy = clangType->getAs<clang::ReferenceType>()) {
323+
clangType = refTy->getPointeeType().getTypePtr();
322324
}
323325
return clangType->castAs<clang::FunctionType>();
324326
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module Reference {
2+
header "reference.h"
3+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#include "reference.h"
2+
#include <utility>
3+
4+
static int staticInt = 42;
5+
6+
int getStaticInt() { return staticInt; }
7+
int &getStaticIntRef() { return staticInt; }
8+
int &&getStaticIntRvalueRef() { return std::move(staticInt); }
9+
const int &getConstStaticIntRef() { return staticInt; }
10+
const int &&getConstStaticIntRvalueRef() { return std::move(staticInt); }
11+
12+
void setStaticInt(int i) { staticInt = i; }
13+
void setStaticIntRef(int &i) { staticInt = i; }
14+
void setStaticIntRvalueRef(int &&i) { staticInt = i; }
15+
void setConstStaticIntRef(const int &i) { staticInt = i; }
16+
void setConstStaticIntRvalueRef(const int &&i) { staticInt = i; }
17+
18+
auto getFuncRef() -> int (&)() { return getStaticInt; }
19+
auto getFuncRvalueRef() -> int (&&)() { return getStaticInt; }
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef TEST_INTEROP_CXX_REFERENCE_INPUTS_REFERENCE_H
2+
#define TEST_INTEROP_CXX_REFERENCE_INPUTS_REFERENCE_H
3+
4+
int getStaticInt();
5+
int &getStaticIntRef();
6+
int &&getStaticIntRvalueRef();
7+
const int &getConstStaticIntRef();
8+
const int &&getConstStaticIntRvalueRef();
9+
10+
void setStaticInt(int);
11+
void setStaticIntRef(int &);
12+
void setStaticIntRvalueRef(int &&);
13+
void setConstStaticIntRef(const int &);
14+
void setConstStaticIntRvalueRef(const int &&);
15+
16+
auto getFuncRef() -> int (&)();
17+
auto getFuncRvalueRef() -> int (&&)();
18+
19+
#endif // TEST_INTEROP_CXX_REFERENCE_INPUTS_REFERENCE_H
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// RUN: %target-swift-emit-ir -I %S/Inputs -enable-cxx-interop %s | %FileCheck %s
2+
3+
import Reference
4+
5+
public func getCxxRef() -> UnsafeMutablePointer<CInt> {
6+
return getStaticIntRef()
7+
}
8+
9+
// CHECK: define {{(protected |dllexport )?}}swiftcc i8* @"$s4main9getCxxRefSpys5Int32VGyF"()
10+
// CHECK: call i32* @{{_Z15getStaticIntRefv|"\?getStaticIntRef@@YAAEAHXZ"}}()
11+
12+
public func getConstCxxRef() -> UnsafePointer<CInt> {
13+
return getConstStaticIntRef()
14+
}
15+
16+
// CHECK: define {{(protected |dllexport )?}}swiftcc i8* @"$s4main14getConstCxxRefSPys5Int32VGyF"()
17+
// CHECK: call i32* @{{_Z20getConstStaticIntRefv|"\?getConstStaticIntRef@@YAAEBHXZ"}}()
18+
19+
public func getCxxRvalueRef() -> UnsafeMutablePointer<CInt> {
20+
return getStaticIntRvalueRef()
21+
}
22+
23+
// CHECK: define {{(protected |dllexport )?}}swiftcc i8* @"$s4main15getCxxRvalueRefSpys5Int32VGyF"()
24+
// CHECK: call i32* @{{_Z21getStaticIntRvalueRefv|"\?getStaticIntRvalueRef@@YA\$\$QEAHXZ"}}()
25+
26+
public func getConstCxxRvalueRef() -> UnsafePointer<CInt> {
27+
return getConstStaticIntRvalueRef()
28+
}
29+
30+
// CHECK: define {{(protected |dllexport )?}}swiftcc i8* @"$s4main20getConstCxxRvalueRefSPys5Int32VGyF"()
31+
// CHECK: call i32* @{{_Z26getConstStaticIntRvalueRefv|"\?getConstStaticIntRvalueRef@@YA\$\$QEBHXZ"}}()
32+
33+
public func setCxxRef() {
34+
var val: CInt = 21
35+
withUnsafeMutablePointer(to: &val) {
36+
setStaticIntRef($0)
37+
}
38+
}
39+
40+
// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main9setCxxRefyyF"()
41+
// CHECK: call void @{{_Z15setStaticIntRefRi|"\?setStaticIntRef@@YAXAEAH@Z"}}(i32* {{nonnull %val|%2}})
42+
43+
public func setCxxConstRef() {
44+
var val: CInt = 21
45+
withUnsafePointer(to: &val) {
46+
setConstStaticIntRef($0)
47+
}
48+
}
49+
50+
// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main14setCxxConstRefyyF"()
51+
// CHECK: call void @{{_Z20setConstStaticIntRefRKi|"\?setConstStaticIntRef@@YAXAEBH@Z"}}(i32* {{nonnull %val|%2}})
52+
53+
public func setCxxRvalueRef() {
54+
var val: CInt = 21
55+
withUnsafeMutablePointer(to: &val) {
56+
setStaticIntRvalueRef($0)
57+
}
58+
}
59+
60+
// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main15setCxxRvalueRefyyF"()
61+
// CHECK: call void @{{_Z21setStaticIntRvalueRefOi|"\?setStaticIntRvalueRef@@YAX\$\$QEAH@Z"}}(i32* {{nonnull %val|%2}})
62+
63+
public func setCxxConstRvalueRef() {
64+
var val: CInt = 21
65+
withUnsafePointer(to: &val) {
66+
setConstStaticIntRvalueRef($0)
67+
}
68+
}
69+
70+
// CHECK: define {{(protected |dllexport )?}}swiftcc void @"$s4main20setCxxConstRvalueRefyyF"()
71+
// CHECK: call void @{{_Z26setConstStaticIntRvalueRefOKi|"\?setConstStaticIntRvalueRef@@YAX\$\$QEBH@Z"}}(i32* {{nonnull %val|%2}})
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %target-swift-ide-test -print-module -module-to-print=Reference -I %S/Inputs -source-filename=x -enable-cxx-interop | %FileCheck %s
2+
3+
// CHECK: func getStaticInt() -> Int32
4+
// CHECK: func getStaticIntRef() -> UnsafeMutablePointer<Int32>
5+
// CHECK: func getStaticIntRvalueRef() -> UnsafeMutablePointer<Int32>
6+
// CHECK: func getConstStaticIntRef() -> UnsafePointer<Int32>
7+
// CHECK: func getConstStaticIntRvalueRef() -> UnsafePointer<Int32>
8+
// CHECK: func setStaticInt(_: Int32)
9+
// CHECK: func setStaticIntRef(_: UnsafeMutablePointer<Int32>)
10+
// CHECK: func setStaticIntRvalueRef(_: UnsafeMutablePointer<Int32>)
11+
// CHECK: func setConstStaticIntRef(_: UnsafePointer<Int32>)
12+
// CHECK: func setConstStaticIntRvalueRef(_: UnsafePointer<Int32>)
13+
// CHECK: func getFuncRef() -> @convention(c) () -> Int32
14+
// CHECK: func getFuncRvalueRef() -> @convention(c) () -> Int32
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// RUN: %target-swift-emit-sil -I %S/Inputs -enable-cxx-interop %s | %FileCheck %s
2+
3+
import Reference
4+
5+
func getCxxRef() -> UnsafeMutablePointer<CInt> {
6+
return getStaticIntRef()
7+
}
8+
9+
// CHECK: sil hidden @$s4main9getCxxRefSpys5Int32VGyF : $@convention(thin) () -> UnsafeMutablePointer<Int32>
10+
// CHECK: [[REF:%.*]] = function_ref @{{_Z15getStaticIntRefv|\?getStaticIntRef@@YAAEAHXZ}} : $@convention(c) () -> UnsafeMutablePointer<Int32>
11+
// CHECK: apply [[REF]]() : $@convention(c) () -> UnsafeMutablePointer<Int32>
12+
13+
func getConstCxxRef() -> UnsafePointer<CInt> {
14+
return getConstStaticIntRef()
15+
}
16+
17+
// CHECK: sil hidden @$s4main14getConstCxxRefSPys5Int32VGyF : $@convention(thin) () -> UnsafePointer<Int32>
18+
// CHECK: [[REF:%.*]] = function_ref @{{_Z20getConstStaticIntRefv|\?getConstStaticIntRef@@YAAEBHXZ}} : $@convention(c) () -> UnsafePointer<Int32>
19+
// CHECK: apply [[REF]]() : $@convention(c) () -> UnsafePointer<Int32>
20+
21+
func getCxxRvalueRef() -> UnsafeMutablePointer<CInt> {
22+
return getStaticIntRvalueRef()
23+
}
24+
25+
// CHECK: sil hidden @$s4main15getCxxRvalueRefSpys5Int32VGyF : $@convention(thin) () -> UnsafeMutablePointer<Int32>
26+
// CHECK: [[REF:%.*]] = function_ref @{{_Z21getStaticIntRvalueRefv|\?getStaticIntRvalueRef@@YA\$\$QEAHXZ}} : $@convention(c) () -> UnsafeMutablePointer<Int32>
27+
// CHECK: apply [[REF]]() : $@convention(c) () -> UnsafeMutablePointer<Int32>
28+
29+
func getConstCxxRvalueRef() -> UnsafePointer<CInt> {
30+
return getConstStaticIntRvalueRef()
31+
}
32+
33+
// CHECK: sil hidden @$s4main20getConstCxxRvalueRefSPys5Int32VGyF : $@convention(thin) () -> UnsafePointer<Int32>
34+
// CHECK: [[REF:%.*]] = function_ref @{{_Z26getConstStaticIntRvalueRefv|\?getConstStaticIntRvalueRef@@YA\$\$QEBHXZ}} : $@convention(c) () -> UnsafePointer<Int32>
35+
// CHECK: apply [[REF]]() : $@convention(c) () -> UnsafePointer<Int32>
36+
37+
func setCxxRef() {
38+
var val: CInt = 21
39+
withUnsafeMutablePointer(to: &val) {
40+
setStaticIntRef($0)
41+
}
42+
}
43+
44+
// CHECK: // closure #1 in setCxxRef()
45+
// CHECK: sil private @$s4main9setCxxRefyyFySpys5Int32VGXEfU_ : $@convention(thin) (UnsafeMutablePointer<Int32>) -> ()
46+
// CHECK: [[REF:%.*]] = function_ref @{{_Z15setStaticIntRefRi|\?setStaticIntRef@@YAXAEAH@Z}} : $@convention(c) (UnsafeMutablePointer<Int32>) -> ()
47+
// CHECK: apply [[REF]](%0) : $@convention(c) (UnsafeMutablePointer<Int32>) -> ()
48+
49+
func setCxxConstRef() {
50+
var val: CInt = 21
51+
withUnsafePointer(to: &val) {
52+
setConstStaticIntRef($0)
53+
}
54+
}
55+
56+
// CHECK: // closure #1 in setCxxConstRef()
57+
// CHECK: sil private @$s4main14setCxxConstRefyyFySPys5Int32VGXEfU_ : $@convention(thin) (UnsafePointer<Int32>) -> ()
58+
// CHECK: [[REF:%.*]] = function_ref @{{_Z20setConstStaticIntRefRKi|\?setConstStaticIntRef@@YAXAEBH@Z}} : $@convention(c) (UnsafePointer<Int32>) -> ()
59+
// CHECK: apply [[REF]](%0) : $@convention(c) (UnsafePointer<Int32>) -> ()
60+
61+
func setCxxRvalueRef() {
62+
var val: CInt = 21
63+
withUnsafeMutablePointer(to: &val) {
64+
setStaticIntRvalueRef($0)
65+
}
66+
}
67+
68+
// CHECK: // closure #1 in setCxxRvalueRef()
69+
// CHECK: sil private @$s4main15setCxxRvalueRefyyFySpys5Int32VGXEfU_ : $@convention(thin) (UnsafeMutablePointer<Int32>) -> ()
70+
// CHECK: [[REF:%.*]] = function_ref @{{_Z21setStaticIntRvalueRefOi|\?setStaticIntRvalueRef@@YAX\$\$QEAH@Z}} : $@convention(c) (UnsafeMutablePointer<Int32>) -> ()
71+
// CHECK: apply [[REF]](%0) : $@convention(c) (UnsafeMutablePointer<Int32>) -> ()
72+
73+
func setCxxConstRvalueRef() {
74+
var val: CInt = 21
75+
withUnsafePointer(to: &val) {
76+
setConstStaticIntRvalueRef($0)
77+
}
78+
}
79+
80+
// CHECK: // closure #1 in setCxxConstRvalueRef()
81+
// CHECK: sil private @$s4main20setCxxConstRvalueRefyyFySPys5Int32VGXEfU_ : $@convention(thin) (UnsafePointer<Int32>) -> ()
82+
// CHECK: [[REF:%.*]] = function_ref @{{_Z26setConstStaticIntRvalueRefOKi|\?setConstStaticIntRvalueRef@@YAX\$\$QEBH@Z}} : $@convention(c) (UnsafePointer<Int32>) -> ()
83+
// CHECK: apply [[REF]](%0) : $@convention(c) (UnsafePointer<Int32>) -> ()

0 commit comments

Comments
 (0)