Skip to content

Commit 6d5ff20

Browse files
committed
IRGen: Implement support for __attribute__((ns_consumed)) block parameters
Fixes <rdar://problem/48792177>.
1 parent 3d9587c commit 6d5ff20

File tree

5 files changed

+58
-3
lines changed

5 files changed

+58
-3
lines changed

lib/IRGen/GenClangType.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,10 @@ clang::CanQualType GenClangType::visitSILFunctionType(CanSILFunctionType type) {
585585
}
586586

587587
SmallVector<clang::QualType, 4> paramTypes;
588+
SmallVector<clang::FunctionProtoType::ExtParameterInfo, 4> extParamInfos;
588589
for (auto paramTy : type->getParameters()) {
590+
clang::FunctionProtoType::ExtParameterInfo extParamInfo;
591+
589592
// Blocks should only take direct +0 parameters.
590593
switch (paramTy.getConvention()) {
591594
case ParameterConvention::Direct_Guaranteed:
@@ -594,7 +597,9 @@ clang::CanQualType GenClangType::visitSILFunctionType(CanSILFunctionType type) {
594597
break;
595598

596599
case ParameterConvention::Direct_Owned:
597-
llvm_unreachable("block takes owned parameter");
600+
extParamInfo = extParamInfo.withIsConsumed(true);
601+
break;
602+
598603
case ParameterConvention::Indirect_In:
599604
case ParameterConvention::Indirect_In_Constant:
600605
case ParameterConvention::Indirect_Inout:
@@ -606,12 +611,16 @@ clang::CanQualType GenClangType::visitSILFunctionType(CanSILFunctionType type) {
606611
paramTy.getArgumentType(IGM.getSILModule(), type));
607612
if (param.isNull())
608613
return clang::CanQualType();
614+
609615
paramTypes.push_back(param);
616+
extParamInfos.push_back(extParamInfo);
610617
}
611618

612619
// Build the Clang function type.
613-
clang::FunctionProtoType::ExtProtoInfo defaultEPI;
614-
auto fnTy = clangCtx.getFunctionType(resultType, paramTypes, defaultEPI);
620+
clang::FunctionProtoType::ExtProtoInfo extProtoInfo;
621+
extProtoInfo.ExtParameterInfos = extParamInfos.begin();
622+
623+
auto fnTy = clangCtx.getFunctionType(resultType, paramTypes, extProtoInfo);
615624
clang::QualType ptrTy;
616625

617626
switch (kind) {

test/IRGen/Inputs/usr/include/Gizmo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ typedef long NSInteger;
4545
- (void) setFrame: (struct NSRect) rect;
4646
- (void) frob;
4747
- (void) test: (struct Fob) fob;
48+
- (void) perform: (void (^)(NS_CONSUMED Gizmo*)) block;
4849
+ (void) runce;
4950
@end
5051

test/IRGen/objc_block_consumed.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
// RUN: %empty-directory(%t)
3+
// RUN: %build-irgen-test-overlays
4+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-ir -disable-objc-attr-requires-foundation-module
5+
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-silgen -disable-objc-attr-requires-foundation-module | %FileCheck %s
6+
7+
// We want to test that IRGen doesn't assert on this code. SIL is the best place
8+
// to file check that the block parameter is actually +1.
9+
10+
// REQUIRES: CPU=x86_64
11+
// REQUIRES: objc_interop
12+
13+
import gizmo
14+
15+
// CHECK-LABEL: sil hidden [ossa] @$s19objc_block_consumed24passBlockWithConsumedArgyySo5GizmoC_ADtF : $@convention(thin) (@guaranteed Gizmo, @guaranteed Gizmo) -> () {
16+
func passBlockWithConsumedArg(_ g: Gizmo, _ other: Gizmo) {
17+
// CHECK: objc_method %0 : $Gizmo, #Gizmo.perform!1.foreign : (Gizmo) -> (((Gizmo?) -> ())?) -> (), $@convention(objc_method) (Optional<@convention(block) (@owned Optional<Gizmo>) -> ()>, Gizmo) -> ()
18+
g.perform { other in }
19+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#import <Foundation/Foundation.h>
2+
3+
static inline void takesBlockWithConsumedArg(void (^ block)(NS_RELEASES_ARGUMENT NSObject *x), NSObject *x) {
4+
block(x);
5+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -import-objc-header %S/Inputs/objc_block_consumed.h -o %t/main
3+
// RUN: %target-run %t/main
4+
5+
// REQUIRES: executable_test
6+
// REQUIRES: objc_interop
7+
8+
import Foundation
9+
import StdlibUnittest
10+
11+
class C : NSObject {
12+
var tracked = LifetimeTracked(0)
13+
}
14+
15+
var ObjCBlockConsumedTestSuite = TestSuite("ObjCBlockConsumed")
16+
17+
ObjCBlockConsumedTestSuite.test("Test") {
18+
takesBlockWithConsumedArg({ arg in }, C())
19+
}
20+
21+
runAllTests()

0 commit comments

Comments
 (0)