Skip to content

Commit 3ee84e9

Browse files
Merge pull request #4942 from swiftwasm/main
[pull] swiftwasm from main
2 parents 67affbd + 4ee32b5 commit 3ee84e9

File tree

6 files changed

+243
-1
lines changed

6 files changed

+243
-1
lines changed

lib/PrintAsClang/PrintClangFunction.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "swift/ClangImporter/ClangImporter.h"
2929
#include "swift/IRGen/IRABIDetailsProvider.h"
3030
#include "clang/AST/ASTContext.h"
31+
#include "clang/AST/DeclObjC.h"
3132
#include "llvm/ADT/STLExtras.h"
3233

3334
using namespace swift;
@@ -68,6 +69,11 @@ bool isKnownType(Type t, PrimitiveTypeMapping &typeMapping,
6869
if (nullableInfo && nullableInfo->canBeNullable)
6970
return true;
7071
}
72+
if (auto *classType = dyn_cast<ClassType>(tPtr)) {
73+
return classType->getClassOrBoundGenericClass()->hasClangNode() &&
74+
isa<clang::ObjCInterfaceDecl>(
75+
classType->getClassOrBoundGenericClass()->getClangDecl());
76+
}
7177

7278
if (auto *structDecl = t->getStructOrBoundGenericStruct())
7379
typeDecl = structDecl;
@@ -260,6 +266,20 @@ class CFunctionSignatureTypePrinter
260266
ClangRepresentation visitClassType(ClassType *CT,
261267
Optional<OptionalTypeKind> optionalKind,
262268
bool isInOutParam) {
269+
auto *cd = CT->getDecl();
270+
if (cd->hasClangNode()) {
271+
ClangSyntaxPrinter(os).printIdentifier(
272+
cast<clang::NamedDecl>(cd->getClangDecl())->getName());
273+
os << " *"
274+
<< (!optionalKind || *optionalKind == OTK_None ? "_Nonnull"
275+
: "_Nullable");
276+
if (isInOutParam) {
277+
os << " __strong";
278+
printInoutTypeModifier();
279+
}
280+
// FIXME: Mark that this is only ObjC representable.
281+
return ClangRepresentation::representable;
282+
}
263283
// FIXME: handle optionalKind.
264284
if (languageMode != OutputLanguageMode::Cxx) {
265285
os << "void * "
@@ -902,6 +922,12 @@ void DeclAndTypeClangFunctionPrinter::printCxxToCFunctionParameterUse(
902922
}
903923

904924
if (auto *classDecl = type->getClassOrBoundGenericClass()) {
925+
if (classDecl->hasClangNode()) {
926+
if (isInOut)
927+
os << '&';
928+
namePrinter();
929+
return;
930+
}
905931
ClangClassTypePrinter::printParameterCxxtoCUseScaffold(
906932
os, classDecl, moduleContext, namePrinter, isInOut);
907933
return;
@@ -1111,6 +1137,7 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
11111137
return;
11121138
}
11131139
if (auto *classDecl = resultTy->getClassOrBoundGenericClass()) {
1140+
assert(!classDecl->hasClangNode());
11141141
ClangClassTypePrinter::printClassTypeReturnScaffold(
11151142
os, classDecl, moduleContext,
11161143
[&]() { printCallToCFunc(/*additionalParam=*/None); });
@@ -1146,6 +1173,20 @@ void DeclAndTypeClangFunctionPrinter::printCxxThunkBody(
11461173
}
11471174
}
11481175

1176+
auto nonOptResultType = resultTy->getOptionalObjectType();
1177+
if (!nonOptResultType)
1178+
nonOptResultType = resultTy;
1179+
if (auto *classDecl = nonOptResultType->getClassOrBoundGenericClass()) {
1180+
assert(classDecl->hasClangNode());
1181+
assert(isa<clang::ObjCContainerDecl>(classDecl->getClangDecl()));
1182+
os << "return (__bridge_transfer ";
1183+
ClangSyntaxPrinter(os).printIdentifier(
1184+
cast<clang::NamedDecl>(classDecl->getClangDecl())->getName());
1185+
os << " *)(__bridge void *)";
1186+
printCallToCFunc(/*additionalParam=*/None);
1187+
os << ";\n";
1188+
return;
1189+
}
11491190
// Primitive values are returned directly without any conversions.
11501191
// Assign the function return value to a variable if the function can throw.
11511192
if (!resultTy->isVoid() && hasThrows)
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -typecheck %t/use-objc-types.swift -typecheck -module-name UseObjCTy -emit-clang-header-path %t/UseObjCTy.h -I %t -enable-experimental-cxx-interop -clang-header-expose-public-decls
5+
6+
// RUN: %target-interop-build-clangxx -std=c++20 -fobjc-arc -c %t/use-swift-objc-types.mm -I %t -o %t/swift-objc-execution.o
7+
// RUN: %target-interop-build-swift %t/use-objc-types.swift -o %t/swift-objc-execution -Xlinker %t/swift-objc-execution.o -module-name UseObjCTy -Xfrontend -entry-point-function-name -Xfrontend swiftMain -I %t
8+
9+
// RUN: %target-codesign %t/swift-objc-execution
10+
// RUN: %target-run %t/swift-objc-execution | %FileCheck %s
11+
// RUN: %target-run %t/swift-objc-execution | %FileCheck --check-prefix=DESTROY %s
12+
13+
// REQUIRES: executable_test
14+
// REQUIRES: objc_interop
15+
16+
//--- header.h
17+
18+
#import <Foundation/Foundation.h>
19+
20+
@interface ObjCKlass: NSObject
21+
-(ObjCKlass * _Nonnull) init:(int)x;
22+
-(int)getValue;
23+
@end
24+
25+
//--- module.modulemap
26+
module ObjCTest {
27+
header "header.h"
28+
}
29+
30+
//--- use-objc-types.swift
31+
import ObjCTest
32+
33+
public func retObjClass() -> ObjCKlass {
34+
return ObjCKlass(1)
35+
}
36+
37+
public func retObjClassNull() -> ObjCKlass? {
38+
return nil
39+
}
40+
41+
public func retObjClassNullable() -> ObjCKlass? {
42+
return retObjClass()
43+
}
44+
45+
public func takeObjCClass(_ x: ObjCKlass) {
46+
print("OBJClass:", x.getValue());
47+
}
48+
49+
public func takeObjCClassInout(_ x: inout ObjCKlass) {
50+
x = ObjCKlass(x.getValue() + 1)
51+
}
52+
53+
public func takeObjCClassNullable(_ x: ObjCKlass?) {
54+
if let x = x {
55+
print("OBJClass:", x.getValue());
56+
} else {
57+
print("NIL");
58+
}
59+
}
60+
61+
public func passThroughObjClass(_ x: ObjCKlass?) -> ObjCKlass? {
62+
return x
63+
}
64+
65+
//--- use-swift-objc-types.mm
66+
67+
#include "header.h"
68+
#include "UseObjCTy.h"
69+
#include <assert.h>
70+
#include <stdio.h>
71+
72+
int globalCounter = 0;
73+
74+
struct DeinitPrinter {
75+
~DeinitPrinter() {
76+
puts("destroy ObjCKlass");
77+
--globalCounter;
78+
}
79+
};
80+
81+
@implementation ObjCKlass {
82+
int _x;
83+
DeinitPrinter _printer;
84+
}
85+
- (ObjCKlass * _Nonnull) init:(int)x {
86+
ObjCKlass *result = [super init];
87+
result->_x = x;
88+
puts("create ObjCKlass");
89+
++globalCounter;
90+
return result;
91+
}
92+
93+
-(int)getValue {
94+
return self->_x;
95+
}
96+
97+
@end
98+
99+
int main() {
100+
using namespace UseObjCTy;
101+
@autoreleasepool {
102+
ObjCKlass* val = retObjClass();
103+
assert(val.getValue == 1);
104+
assert(globalCounter == 1);
105+
takeObjCClass(val);
106+
takeObjCClassInout(val);
107+
takeObjCClassNullable(val);
108+
takeObjCClassNullable(retObjClassNull());
109+
}
110+
assert(globalCounter == 0);
111+
// CHECK: create ObjCKlass
112+
// CHECK-NEXT: OBJClass: 1
113+
// CHECK-NEXT: create ObjCKlass
114+
// CHECK: OBJClass: 2
115+
// CHECK-NEXT: NIL
116+
// DESTROY: destroy ObjCKlass
117+
// DESTROY: destroy ObjCKlass
118+
puts("Part2");
119+
@autoreleasepool {
120+
ObjCKlass* val = retObjClassNullable();
121+
assert(globalCounter == 1);
122+
assert(val.getValue == 1);
123+
takeObjCClassNullable(passThroughObjClass(val));
124+
}
125+
assert(globalCounter == 0);
126+
// CHECK: Part2
127+
// CHECK-NEXT: create ObjCKlass
128+
// CHECK-NEXT: OBJClass: 1
129+
// CHECK-NEXT: destroy ObjCKlass
130+
// DESTROY: destroy ObjCKlass
131+
return 0;
132+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: split-file %s %t
3+
4+
// RUN: %target-swift-frontend -typecheck %t/use-objc-types.swift -typecheck -module-name UseObjCTy -emit-clang-header-path %t/UseObjCTy.h -I %t -enable-experimental-cxx-interop -clang-header-expose-public-decls
5+
6+
// RUN: %FileCheck %s < %t/UseObjCTy.h
7+
8+
// FIXME: remove once https://github.com/apple/swift/pull/60971 lands.
9+
// RUN: echo "#include \"header.h\"" > %t/full-header.h
10+
// RUN: cat %t/UseObjCTy.h >> %t/full-header.h
11+
12+
// RUN: %target-interop-build-clangxx -std=gnu++20 -fobjc-arc -c -x objective-c++-header %t/full-header.h -o %t/o.o
13+
14+
// REQUIRES: objc_interop
15+
16+
//--- header.h
17+
18+
@interface ObjCKlass
19+
-(ObjCKlass * _Nonnull) init;
20+
@end
21+
22+
//--- module.modulemap
23+
module ObjCTest {
24+
header "header.h"
25+
}
26+
27+
//--- use-objc-types.swift
28+
import ObjCTest
29+
30+
public func retObjClass() -> ObjCKlass {
31+
return ObjCKlass()
32+
}
33+
34+
public func takeObjCClass(_ x: ObjCKlass) {
35+
}
36+
37+
public func takeObjCClassInout(_ x: inout ObjCKlass) {
38+
}
39+
40+
public func takeObjCClassNullable(_ x: ObjCKlass?) {
41+
}
42+
43+
public func retObjClassNullable() -> ObjCKlass? {
44+
return nil
45+
}
46+
47+
// CHECK: ObjCKlass *_Nonnull $s9UseObjCTy03retB5ClassSo0B6CKlassCyF(void) SWIFT_NOEXCEPT SWIFT_CALL;
48+
// CHECK-NEXT: ObjCKlass *_Nullable $s9UseObjCTy03retB13ClassNullableSo0B6CKlassCSgyF(void) SWIFT_NOEXCEPT SWIFT_CALL;
49+
// CHECK-NEXT: void $s9UseObjCTy04takeB6CClassyySo0B6CKlassCF(ObjCKlass *_Nonnull x) SWIFT_NOEXCEPT SWIFT_CALL;
50+
// CHECK-NEXT: void $s9UseObjCTy04takeB11CClassInoutyySo0B6CKlassCzF(ObjCKlass *_Nonnull __strong * _Nonnull x) SWIFT_NOEXCEPT SWIFT_CALL;
51+
// CHECK-NEXT: void $s9UseObjCTy04takeB14CClassNullableyySo0B6CKlassCSgF(ObjCKlass *_Nullable x) SWIFT_NOEXCEPT SWIFT_CALL;
52+
53+
// CHECK: inline ObjCKlass *_Nonnull retObjClass() noexcept SWIFT_WARN_UNUSED_RESULT {
54+
// CHECK-NEXT: return (__bridge_transfer ObjCKlass *)(__bridge void *)_impl::$s9UseObjCTy03retB5ClassSo0B6CKlassCyF();
55+
56+
// CHECK: inline ObjCKlass *_Nullable retObjClassNullable() noexcept SWIFT_WARN_UNUSED_RESULT {
57+
// CHECK-NEXT: return (__bridge_transfer ObjCKlass *)(__bridge void *)_impl::$s9UseObjCTy03retB13ClassNullableSo0B6CKlassCSgyF();
58+
59+
// CHECK: void takeObjCClass(ObjCKlass *_Nonnull x) noexcept {
60+
// CHECK-NEXT: return _impl::$s9UseObjCTy04takeB6CClassyySo0B6CKlassCF(x);
61+
62+
// CHECK: inline void takeObjCClassInout(ObjCKlass *_Nonnull __strong & x) noexcept {
63+
// CHECK-NEXT: return _impl::$s9UseObjCTy04takeB11CClassInoutyySo0B6CKlassCzF(&x);
64+
65+
// CHECK: inline void takeObjCClassNullable(ObjCKlass *_Nullable x) noexcept {
66+
// CHECK-NEXT: return _impl::$s9UseObjCTy04takeB14CClassNullableyySo0B6CKlassCSgF(x);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
config.suffixes = ['.swift', '.cpp', '.mm']

utils/build-tooling-libs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ class Builder(object):
271271
"-DEXPERIMENTAL_STRING_PROCESSING_SOURCE_DIR=" +
272272
os.path.join(SWIFT_SOURCE_ROOT,
273273
"swift-experimental-string-processing"),
274+
"-DSWIFT_PATH_TO_SWIFT_SYNTAX_SOURCE=" +
275+
os.path.join(SWIFT_SOURCE_ROOT, "swift-syntax"),
274276
]
275277

276278
llvm_src_path = os.path.join(SWIFT_SOURCE_ROOT, "llvm") \

utils/dev-scripts/split-cmdline

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
#
1414
# Split swift compiler command lines into multiple lines.
1515
#
16-
# Reads the command line from stdin an outputs the split line to stdout.
16+
# Reads the command line from stdin and outputs the split line to stdout.
1717
# Example:
1818
#
1919
# $ swiftc -c hello.swift -### | split-cmdline

0 commit comments

Comments
 (0)