Skip to content

Commit cbd4b3a

Browse files
committed
[cxx-interop] Add support for SWIFT_RETURNS_(UN)RETAINED for ObjC APIs returning C++ FRT
rdar://135360972
1 parent 8553f99 commit cbd4b3a

File tree

3 files changed

+58
-29
lines changed

3 files changed

+58
-29
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 25 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,25 @@ class Conventions {
12981298
}
12991299
llvm_unreachable("unhandled ownership");
13001300
}
1301+
1302+
// Determines owned/unowned ResultConvention of the returned value based on
1303+
// returns_retained/returns_unretained attribute.
1304+
std::optional<ResultConvention>
1305+
getCxxRefConventionWithAttrs(const TypeLowering &tl,
1306+
const clang::Decl *decl) const {
1307+
if (tl.getLoweredType().isForeignReferenceType() && decl->hasAttrs()) {
1308+
for (const auto *attr : decl->getAttrs()) {
1309+
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
1310+
if (swiftAttr->getAttribute() == "returns_unretained") {
1311+
return ResultConvention::Unowned;
1312+
} else if (swiftAttr->getAttribute() == "returns_retained") {
1313+
return ResultConvention::Owned;
1314+
}
1315+
}
1316+
}
1317+
}
1318+
return std::nullopt;
1319+
}
13011320
};
13021321

13031322
/// A visitor for breaking down formal result types into a SILResultInfo
@@ -3340,8 +3359,11 @@ class ObjCMethodConventions : public Conventions {
33403359
if (isImplicitPlusOneCFResult())
33413360
return ResultConvention::Owned;
33423361

3343-
if (tl.getLoweredType().isForeignReferenceType())
3362+
if (tl.getLoweredType().isForeignReferenceType()) {
3363+
if (auto resultConventionOpt = getCxxRefConventionWithAttrs(tl, Method))
3364+
return *resultConventionOpt;
33443365
return ResultConvention::Unowned;
3366+
}
33453367

33463368
return ResultConvention::Autoreleased;
33473369
}
@@ -3381,25 +3403,6 @@ class CFunctionTypeConventions : public Conventions {
33813403
const clang::FunctionType *type)
33823404
: Conventions(kind), FnType(type) {}
33833405

3384-
// Determines owned/unowned ResultConvention of the returned value based on
3385-
// returns_retained/returns_unretained attribute.
3386-
std::optional<ResultConvention>
3387-
getForeignReferenceTypeResultConventionWithAttributes(
3388-
const TypeLowering &tl, const clang::FunctionDecl *decl) const {
3389-
if (tl.getLoweredType().isForeignReferenceType() && decl->hasAttrs()) {
3390-
for (const auto *attr : decl->getAttrs()) {
3391-
if (const auto *swiftAttr = dyn_cast<clang::SwiftAttrAttr>(attr)) {
3392-
if (swiftAttr->getAttribute() == "returns_unretained") {
3393-
return ResultConvention::Unowned;
3394-
} else if (swiftAttr->getAttribute() == "returns_retained") {
3395-
return ResultConvention::Owned;
3396-
}
3397-
}
3398-
}
3399-
}
3400-
return std::nullopt;
3401-
}
3402-
34033406
public:
34043407
CFunctionTypeConventions(const clang::FunctionType *type)
34053408
: Conventions(ConventionsKind::CFunctionType), FnType(type) {}
@@ -3517,11 +3520,7 @@ class CFunctionConventions : public CFunctionTypeConventions {
35173520
return ResultConvention::Indirect;
35183521
}
35193522

3520-
// Explicitly setting the ownership of the returned FRT if the C++
3521-
// global/free function has either swift_attr("returns_retained") or
3522-
// ("returns_unretained") attribute.
3523-
if (auto resultConventionOpt =
3524-
getForeignReferenceTypeResultConventionWithAttributes(tl, TheDecl))
3523+
if (auto resultConventionOpt = getCxxRefConventionWithAttrs(tl, TheDecl))
35253524
return *resultConventionOpt;
35263525

35273526
if (isCFTypedef(tl, TheDecl->getReturnType())) {
@@ -3603,11 +3602,8 @@ class CXXMethodConventions : public CFunctionTypeConventions {
36033602
return ResultConvention::Indirect;
36043603
}
36053604

3606-
// Explicitly setting the ownership of the returned FRT if the C++ member
3607-
// method has either swift_attr("returns_retained") or
3608-
// ("returns_unretained") attribute.
36093605
if (auto resultConventionOpt =
3610-
getForeignReferenceTypeResultConventionWithAttributes(resultTL, TheDecl))
3606+
getCxxRefConventionWithAttrs(resultTL, TheDecl))
36113607
return *resultConventionOpt;
36123608

36133609
if (TheDecl->hasAttr<clang::CFReturnsRetainedAttr>() &&

test/Interop/Cxx/foreign-reference/Inputs/cxx-functions-and-methods-returning-frt.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#pragma once
2+
#include <Foundation/Foundation.h>
23
#include <functional>
34

45
// FRT or SWIFT_SHARED_REFERENCE type
@@ -326,3 +327,25 @@ struct Derived : Base {
326327
FRTStruct *_Nonnull VirtualMethodReturningFRTUnowned() override
327328
__attribute__((swift_attr("returns_unretained")));
328329
};
330+
331+
@interface Bridge : NSObject
332+
333+
+ (struct FRTStruct *_Nonnull)objCMethodReturningFRTUnannotated;
334+
+ (struct FRTStruct *_Nonnull)objCMethodReturningFRTUnowned
335+
__attribute__((swift_attr("returns_unretained")));
336+
+ (struct FRTStruct *_Nonnull)objCMethodReturningFRTOwned
337+
__attribute__((swift_attr("returns_retained")));
338+
339+
@end
340+
341+
@implementation Bridge
342+
+ (struct FRTStruct *_Nonnull)objCMethodReturningFRTUnannotated {
343+
};
344+
+ (struct FRTStruct *_Nonnull)objCMethodReturningFRTUnowned
345+
__attribute__((swift_attr("returns_unretained"))) {
346+
}
347+
+ (struct FRTStruct *_Nonnull)objCMethodReturningFRTOwned
348+
__attribute__((swift_attr("returns_retained"))) {
349+
}
350+
351+
@end

test/Interop/Cxx/foreign-reference/frt-retained-unretained-attributes.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,3 +246,13 @@ func testVirtualMethods(base: Base, derived: Derived) {
246246
// CHECK: function_ref @{{.*}}VirtualMethodReturningFRTOwned{{.*}} : $@convention(cxx_method) (@inout Derived) -> @owned FRTStruct
247247
}
248248

249+
func testObjCMethods() {
250+
var frt1 = Bridge.objCMethodReturningFRTUnannotated()
251+
// CHECK: objc_method {{.*}} #Bridge.objCMethodReturningFRTUnannotated!foreign : (Bridge.Type) -> () -> FRTStruct, $@convention(objc_method) (@objc_metatype Bridge.Type) -> FRTStruct
252+
253+
var frt2 = Bridge.objCMethodReturningFRTUnowned()
254+
// CHECK: objc_method {{.*}} #Bridge.objCMethodReturningFRTUnowned!foreign : (Bridge.Type) -> () -> FRTStruct, $@convention(objc_method) (@objc_metatype Bridge.Type) -> FRTStruct
255+
256+
var frt3 = Bridge.objCMethodReturningFRTOwned()
257+
// CHECK: objc_method {{.*}} #Bridge.objCMethodReturningFRTOwned!foreign : (Bridge.Type) -> () -> FRTStruct, $@convention(objc_method) (@objc_metatype Bridge.Type) -> @owned FRTStruct
258+
}

0 commit comments

Comments
 (0)