Skip to content

Commit 612eeff

Browse files
authored
Merge pull request #64911 from hyp/eng/grand-macro-rename
[interop] update names and add docs for the interop C++ helper macros
2 parents 9ee8c73 + 64a4b31 commit 612eeff

File tree

11 files changed

+222
-38
lines changed

11 files changed

+222
-38
lines changed

include/swift/AST/DiagnosticsClangImporter.def

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ NOTE(record_is_dependent, none, "record '%0' is dependent", (StringRef))
165165
NOTE(record_parent_unimportable, none, "record %0's parent is not importable", (StringRef))
166166
NOTE(reference_passed_by_value, none, "function uses foreign reference type "
167167
"'%0' as a value in %1 types which breaks "
168-
"'import_reference' contract (outlined in "
168+
"'swift_shared_reference' contract (outlined in "
169169
"C++ Interop User Manual).",
170170
(StringRef, StringRef))
171171
NOTE(record_not_automatically_importable, none, "record '%0' is not "
@@ -186,11 +186,11 @@ NOTE(projection_reference_not_imported, none, "C++ method '%0' that returns a re
186186
NOTE(projection_may_return_interior_ptr, none, "C++ method '%0' may return an "
187187
"interior pointer. ",
188188
(StringRef))
189-
NOTE(mark_self_contained, none, "Mark type '%0' as 'SELF_CONTAINED' in C++ to "
189+
NOTE(mark_self_contained, none, "Mark type '%0' as 'SWIFT_SELF_CONTAINED' in C++ to "
190190
"make methods that use it available in Swift. ",
191191
(StringRef))
192-
NOTE(mark_safe_to_import, none, "Mark method '%0' as 'SAFE_TO_IMPORT' in C++ to "
193-
"make it available in Swift. ",
192+
NOTE(mark_safe_to_import, none, "annotate method '%0' with 'SWIFT_RETURNS_INDEPENDENT_VALUE' in C++ to "
193+
"make it available in Swift",
194194
(StringRef))
195195

196196
NOTE(at_to_subscript, none, "Do you want to replace it with a call "

lib/ClangImporter/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,16 @@ set(SWIFTINC_DIR
5050

5151
add_custom_command(
5252
OUTPUT "${SWIFTINC_DIR}/bridging"
53+
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/bridging"
5354
COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${CMAKE_CURRENT_SOURCE_DIR}/bridging" "${SWIFTINC_DIR}")
5455

5556
add_custom_target("copy_cxxInterop_support_header"
5657
DEPENDS "${SWIFTINC_DIR}/bridging"
5758
COMMENT "Copying C++ interop support header to ${SWIFTINC_DIR}")
5859

59-
swift_install_in_component(FILES "${CMAKE_CURRENT_SOURCE_DIR}/bridging"
60+
swift_install_in_component(FILES
61+
"${CMAKE_CURRENT_SOURCE_DIR}/bridging"
62+
"${CMAKE_CURRENT_SOURCE_DIR}/module.modulemap"
6063
DESTINATION "include/swift"
6164
COMPONENT compiler)
6265

lib/ClangImporter/ClangImporter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4408,8 +4408,8 @@ static void diagnoseForeignReferenceTypeFixit(ClangImporter::Implementation &Imp
44084408
HeaderLoc loc, Diagnostic diag) {
44094409
auto importedLoc =
44104410
Impl.SwiftContext.getClangModuleLoader()->importSourceLocation(loc.clangLoc);
4411-
Impl.diagnose(loc, diag)
4412-
.fixItInsert(importedLoc, "SWIFT_REFERENCE_TYPE(<#retain#>, <#release#>) ");
4411+
Impl.diagnose(loc, diag).fixItInsert(
4412+
importedLoc, "SWIFT_SHARED_REFERENCE(<#retain#>, <#release#>) ");
44134413
}
44144414

44154415
bool ClangImporter::Implementation::emitDiagnosticsForTarget(

lib/ClangImporter/bridging

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,98 @@
1717
#ifndef SWIFT_CLANGIMPORTER_SWIFT_INTEROP_SUPPORT_H
1818
#define SWIFT_CLANGIMPORTER_SWIFT_INTEROP_SUPPORT_H
1919

20-
#define SELF_CONTAINED __attribute__((swift_attr("import_owned")))
21-
#define SAFE_TO_IMPORT __attribute__((swift_attr("import_unsafe")))
20+
/// Specifies that a C++ `class` or `struct` owns and controls the lifetime of all
21+
/// of the objects it references. Such type should not reference any objects whose
22+
/// lifetime is controlled externally. This annotation allows Swift to import methods
23+
/// that return a `class` or `struct` type that is annotated with this macro.
24+
#define SWIFT_SELF_CONTAINED __attribute__((swift_attr("import_owned")))
25+
26+
/// Specifies that a C++ method returns a value that is presumed to contain
27+
/// objects whose lifetime is not dependent on `this` or other parameters passed
28+
/// to the method.
29+
#define SWIFT_RETURNS_INDEPENDENT_VALUE __attribute__((swift_attr("import_unsafe")))
2230

2331
#define _CXX_INTEROP_STRINGIFY(_x) #_x
24-
#define SWIFT_REFERENCE_TYPE(_retain, _release) \
25-
__attribute__((swift_attr("import_reference"))) \
26-
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:_retain)))) \
32+
33+
/// Specifies that a C++ `class` or `struct` is reference-counted using
34+
/// the given `retain` and `release` functions. This annotation lets Swift import
35+
/// such a type as reference counted type in Swift, taking advantage of Swift's
36+
/// automatic reference counting.
37+
///
38+
/// This example shows how to use this macro to let Swift know that
39+
/// a non-copyable reference counted C++ class can be imported as a reference counted type in Swift:
40+
/// ```c++
41+
/// class SWIFT_SHARED_REFERENCE(retainSharedObject, releaseSharedObject)
42+
/// SharedObject : NonCopyable, IntrusiveReferenceCounted<SharedObject> {
43+
/// public:
44+
/// static SharedObject* create();
45+
/// void doSomething();
46+
/// };
47+
///
48+
/// void retainSharedObject(SharedObject *);
49+
/// void releaseSharedObject(SharedObject *);
50+
/// ```
51+
///
52+
/// Then, the Swift programmer would be able to use it in the following manner:
53+
///
54+
/// ```swift
55+
/// let object = SharedObject.create()
56+
/// object.doSomething()
57+
/// // The Swift compiler will release object here.
58+
/// ```
59+
#define SWIFT_SHARED_REFERENCE(_retain, _release) \
60+
__attribute__((swift_attr("import_reference"))) \
61+
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:_retain)))) \
2762
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:_release))))
2863

64+
/// Specifies that a C++ `class` or `struct` is a reference type whose lifetime
65+
/// is presumed to be immortal, i.e. the reference to such object is presumed to
66+
/// always be valid. This annotation lets Swift import such a type as a reference
67+
/// type in Swift.
68+
////
69+
/// This example shows how to use this macro to let Swift know that
70+
/// a non-copyable singleton C++ class can be imported as a reference type in Swift:
71+
/// ```c++
72+
/// class SWIFT_IMMORTAL_REFERENCE
73+
/// LoggerSingleton : NonCopyable {
74+
/// public:
75+
/// static LoggerSingleton &getInstance();
76+
/// void log(int x);
77+
/// };
78+
/// ```
79+
///
80+
/// Then, the Swift programmer would be able to use it in the following manner:
81+
///
82+
/// ```swift
83+
/// let logger = LoggerSingleton.getInstance()
84+
/// logger.log(123)
85+
/// ```
86+
#define SWIFT_IMMORTAL_REFERENCE \
87+
__attribute__((swift_attr("import_reference"))) \
88+
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:immortal)))) \
89+
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:immortal))))
90+
91+
/// Specifies that a C++ `class` or `struct` is a reference type whose lifetime
92+
/// is not managed automatically. The programmer must validate that any reference
93+
/// to such object is valid themselves. This annotation lets Swift import such a type as a reference type in Swift.
94+
#define SWIFT_UNSAFE_REFERENCE \
95+
__attribute__((swift_attr("import_reference"))) \
96+
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(retain:immortal)))) \
97+
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(release:immortal))))
98+
99+
/// Specifies a name that will be used in Swift for this declaration instead of its original name.
29100
#define SWIFT_NAME(_name) __attribute__((swift_name(#_name)))
30101

31-
#define CONFORMS_TO(_name) \
32-
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(conforms_to:_name))))
102+
/// Specifies that a specific C++ `class` or `struct` conforms to a
103+
/// a specific Swift protocol.
104+
///
105+
/// This example shows how to use this macro to conform a class template to a Swift protocol:
106+
/// ```
107+
/// template<class T>
108+
/// class SWIFT_CONFORMS_TO_PROTOCOL(SwiftModule.ProtocolName)
109+
/// CustomClass {};
110+
/// ```
111+
#define SWIFT_CONFORMS_TO_PROTOCOL(_moduleName_protocolName) \
112+
__attribute__((swift_attr(_CXX_INTEROP_STRINGIFY(conforms_to:_moduleName_protocolName))))
33113

34114
#endif // SWIFT_CLANGIMPORTER_SWIFT_INTEROP_SUPPORT_H

lib/ClangImporter/module.modulemap

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//===------------------ module.modulemap - C++ and Swift module -*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
module SwiftBridging {
14+
header "bridging"
15+
16+
export *
17+
}

lib/Sema/CSDiagnostics.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3910,8 +3910,7 @@ void MissingMemberFailure::diagnoseUnsafeCxxMethod(SourceLoc loc,
39103910
ctx.Diags
39113911
.diagnose(methodSwiftLoc, diag::mark_safe_to_import,
39123912
name.getBaseIdentifier().str())
3913-
.fixItInsert(methodSwiftLoc,
3914-
" SAFE_TO_IMPORT ");
3913+
.fixItInsert(methodSwiftLoc, " SWIFT_RETURNS_INDEPENDENT_VALUE ");
39153914
} else if (cxxMethod->getReturnType()->isReferenceType()) {
39163915
// Rewrite a call to .at(42) as a subscript.
39173916
if (name.getBaseIdentifier().is("at") &&
@@ -3941,8 +3940,7 @@ void MissingMemberFailure::diagnoseUnsafeCxxMethod(SourceLoc loc,
39413940
ctx.Diags
39423941
.diagnose(methodSwiftLoc, diag::mark_safe_to_import,
39433942
name.getBaseIdentifier().str())
3944-
.fixItInsert(methodSwiftLoc,
3945-
" SAFE_TO_IMPORT ");
3943+
.fixItInsert(methodSwiftLoc, " SWIFT_RETURNS_INDEPENDENT_VALUE ");
39463944
}
39473945
} else if (cxxMethod->getReturnType()->isRecordType()) {
39483946
if (auto cxxRecord = dyn_cast<clang::CXXRecordDecl>(
@@ -3967,12 +3965,10 @@ void MissingMemberFailure::diagnoseUnsafeCxxMethod(SourceLoc loc,
39673965
ctx.Diags
39683966
.diagnose(methodSwiftLoc, diag::mark_safe_to_import,
39693967
name.getBaseIdentifier().str())
3970-
.fixItInsert(methodSwiftLoc,
3971-
" SAFE_TO_IMPORT ");
3968+
.fixItInsert(methodSwiftLoc, " SWIFT_RETURNS_INDEPENDENT_VALUE ");
39723969
ctx.Diags
39733970
.diagnose(baseSwiftLoc, diag::mark_self_contained, returnTypeStr)
3974-
.fixItInsert(baseSwiftLoc,
3975-
"SELF_CONTAINED ");
3971+
.fixItInsert(baseSwiftLoc, "SWIFT_SELF_CONTAINED ");
39763972
}
39773973
}
39783974
}

test/Interop/Cxx/class/fixit-add-safe-to-import-self-contained.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,21 @@ struct X {
2121
import Test
2222

2323
public func test(x: X) {
24-
// CHECK: note: Mark method 'test' as 'SAFE_TO_IMPORT' in C++ to make it available in Swift.
24+
// CHECK: note: annotate method 'test' with 'SWIFT_RETURNS_INDEPENDENT_VALUE' in C++ to make it available in Swift
2525
// CHECK: int *test() { }
2626
// CHECK: ^
27-
// CHECK: SAFE_TO_IMPORT
27+
// CHECK: SWIFT_RETURNS_INDEPENDENT_VALUE
2828

2929
x.test()
3030

31-
// CHECK: note: Mark method 'other' as 'SAFE_TO_IMPORT' in C++ to make it available in Swift.
31+
// CHECK: note: annotate method 'other' with 'SWIFT_RETURNS_INDEPENDENT_VALUE' in C++ to make it available in Swift
3232
// CHECK: Ptr other() { }
3333
// CHECK: ^
34-
// CHECK: SAFE_TO_IMPORT
34+
// CHECK: SWIFT_RETURNS_INDEPENDENT_VALUE
3535

36-
// CHECK: note: Mark type 'Ptr' as 'SELF_CONTAINED' in C++ to make methods that use it available in Swift.
36+
// CHECK: note: Mark type 'Ptr' as 'SWIFT_SELF_CONTAINED' in C++ to make methods that use it available in Swift.
3737
// CHECK: struct Ptr {
3838
// CHECK: ^
39-
// CHECK: SELF_CONTAINED
39+
// CHECK: SWIFT_SELF_CONTAINED
4040
x.other()
4141
}

test/Interop/Cxx/class/invalid-class-errors.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ import Test
3030
// CHECK: note: record 'A' is not automatically available: does not have a copy constructor or destructor. Does this type have reference semantics?
3131
// CHECK: struct A {
3232
// CHECK: ^
33-
// CHECK: SWIFT_REFERENCE_TYPE(<#retain#>, <#release#>)
33+
// CHECK: SWIFT_SHARED_REFERENCE(<#retain#>, <#release#>)
3434
public func test(x: A) { }
3535
// CHECK: note: record 'B' is not automatically available: does not have a copy constructor or destructor. Does this type have reference semantics?
3636
// CHECK: struct {{.*}}B {
3737
// CHECK: ^
38-
// CHECK: SWIFT_REFERENCE_TYPE(<#retain#>, <#release#>)
38+
// CHECK: SWIFT_SHARED_REFERENCE(<#retain#>, <#release#>)
3939
public func test(x: B) { }
4040
// CHECK: note: record 'Nested' is not automatically available: does not have a copy constructor or destructor. Does this type have reference semantics?
4141
// CHECK: struct Nested {
4242
// CHECK: ^
43-
// CHECK: SWIFT_REFERENCE_TYPE(<#retain#>, <#release#>)
43+
// CHECK: SWIFT_SHARED_REFERENCE(<#retain#>, <#release#>)
4444
public func test(x: Namespace.Nested) { }

test/Interop/Cxx/class/invalid-unsafe-projection-errors.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ import Test
2929
public func test(x: M) {
3030
// CHECK: note: C++ method 'test1' that returns a pointer of type 'UnsafeMutablePointer' is unavailable.
3131
// CHECK: note: C++ method 'test1' may return an interior pointer.
32-
// CHECK: note: Mark method 'test1' as 'SAFE_TO_IMPORT' in C++ to make it available in Swift.
32+
// CHECK: note: annotate method 'test1' with 'SWIFT_RETURNS_INDEPENDENT_VALUE' in C++ to make it available in Swift
3333
x.test1()
3434
// CHECK: note: C++ method 'test2' that returns a reference of type 'UnsafeMutablePointer' is unavailable.
3535
// CHECK: note: C++ method 'test2' may return an interior pointer.
36-
// CHECK: note: Mark method 'test2' as 'SAFE_TO_IMPORT' in C++ to make it available in Swift.
36+
// CHECK: note: annotate method 'test2' with 'SWIFT_RETURNS_INDEPENDENT_VALUE' in C++ to make it available in Swift
3737
x.test2()
3838
// CHECK: note: C++ method 'test3' that returns a value of type 'Ptr' is unavailable.
3939
// CHECK: note: C++ method 'test3' may return an interior pointer.
40-
// CHECK: note: Mark method 'test3' as 'SAFE_TO_IMPORT' in C++ to make it available in Swift.
41-
// CHECK: note: Mark type 'Ptr' as 'SELF_CONTAINED' in C++ to make methods that use it available in Swift.
40+
// CHECK: note: annotate method 'test3' with 'SWIFT_RETURNS_INDEPENDENT_VALUE' in C++ to make it available in Swift
41+
// CHECK: note: Mark type 'Ptr' as 'SWIFT_SELF_CONTAINED' in C++ to make methods that use it available in Swift.
4242
x.test3()
4343
// CHECK: note: C++ method 'begin' that returns an iterator is unavailable
4444
// CHECK: note: C++ methods that return iterators are potentially unsafe. Try re-writing to use Swift iterator APIs.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// RUN: rm -rf %t
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend %t/SwiftMod.swift -module-name SwiftMod -emit-module -o %t/SwiftMod.swiftmodule -I %t -enable-experimental-cxx-interop -Xcc -DFIRSTPASS
5+
6+
// RUN: %target-swift-ide-test -print-module -module-to-print=SwiftMod -module-to-print=CxxModule -I %t -I %t/Inputs -I %swift_src_root/lib/ClangImporter -source-filename=x -enable-experimental-cxx-interop | %FileCheck %s
7+
8+
// RUN: %target-swift-ide-test -print-module -module-to-print=SwiftMod -module-to-print=CxxModule -I %t -I %t/Inputs -I %swift_src_root/lib/ClangImporter -source-filename=x -enable-experimental-cxx-interop -Xcc -DINCMOD | %FileCheck %s
9+
10+
//--- SwiftMod.swift
11+
12+
public protocol Proto {
13+
}
14+
15+
//--- Inputs/module.modulemap
16+
module CxxModule {
17+
header "header.h"
18+
requires cplusplus
19+
}
20+
21+
//--- Inputs/header.h
22+
23+
// Note: in actuality, this will be included
24+
// as <swift/bridging>, but in this test we include
25+
// it directly.
26+
#ifndef INCMOD
27+
#include "bridging"
28+
#else
29+
#pragma clang module import SwiftBridging
30+
#endif
31+
32+
class SWIFT_SELF_CONTAINED SelfContained {
33+
public:
34+
int *pointer;
35+
36+
SelfContained();
37+
38+
const int *returnsIndependent() const SWIFT_RETURNS_INDEPENDENT_VALUE;
39+
};
40+
41+
class SWIFT_SHARED_REFERENCE(retainSharedObject, releaseSharedObject)
42+
SharedObject {
43+
public:
44+
static SharedObject *create();
45+
};
46+
47+
void retainSharedObject(SharedObject *);
48+
void releaseSharedObject(SharedObject *);
49+
50+
class SWIFT_IMMORTAL_REFERENCE LoggerSingleton {
51+
public:
52+
LoggerSingleton(const LoggerSingleton &) = delete;
53+
static LoggerSingleton *getInstance();
54+
};
55+
56+
class SWIFT_UNSAFE_REFERENCE UnsafeNonCopyable {
57+
public:
58+
UnsafeNonCopyable(UnsafeNonCopyable &) = delete;
59+
};
60+
61+
UnsafeNonCopyable *returnsPointerToUnsafeReference();
62+
void takesPointerToUnsafeNonCopyable(UnsafeNonCopyable *);
63+
64+
class SWIFT_CONFORMS_TO_PROTOCOL(SwiftMod.Proto) ConformsTo {
65+
public:
66+
};
67+
68+
69+
// CHECK: struct SelfContained {
70+
71+
// CHECK: func returnsIndependent() -> UnsafePointer<Int32>!
72+
73+
// CHECK: class SharedObject {
74+
// CHECK: class func create() -> SharedObject!
75+
// CHECK: func retainSharedObject(_: SharedObject!)
76+
// CHECK: func releaseSharedObject(_: SharedObject!)
77+
78+
// CHECK: class LoggerSingleton {
79+
// CHECK: class func getInstance() -> LoggerSingleton!
80+
// CHECK: }
81+
82+
// CHECK: class UnsafeNonCopyable {
83+
// CHECK: }
84+
// CHECK: func returnsPointerToUnsafeReference() -> UnsafeNonCopyable!
85+
// CHECK: func takesPointerToUnsafeNonCopyable(_: UnsafeNonCopyable!)
86+
87+
// CHECK: struct ConformsTo : Proto {
88+

0 commit comments

Comments
 (0)