-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Fixes for __attribute__((ns_consumed)) block parameters #28527
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -585,7 +585,10 @@ clang::CanQualType GenClangType::visitSILFunctionType(CanSILFunctionType type) { | |
} | ||
|
||
SmallVector<clang::QualType, 4> paramTypes; | ||
SmallVector<clang::FunctionProtoType::ExtParameterInfo, 4> extParamInfos; | ||
for (auto paramTy : type->getParameters()) { | ||
clang::FunctionProtoType::ExtParameterInfo extParamInfo; | ||
|
||
// Blocks should only take direct +0 parameters. | ||
switch (paramTy.getConvention()) { | ||
case ParameterConvention::Direct_Guaranteed: | ||
|
@@ -594,7 +597,9 @@ clang::CanQualType GenClangType::visitSILFunctionType(CanSILFunctionType type) { | |
break; | ||
|
||
case ParameterConvention::Direct_Owned: | ||
llvm_unreachable("block takes owned parameter"); | ||
extParamInfo = extParamInfo.withIsConsumed(true); | ||
break; | ||
|
||
case ParameterConvention::Indirect_In: | ||
case ParameterConvention::Indirect_In_Constant: | ||
case ParameterConvention::Indirect_Inout: | ||
|
@@ -606,12 +611,16 @@ clang::CanQualType GenClangType::visitSILFunctionType(CanSILFunctionType type) { | |
paramTy.getArgumentType(IGM.getSILModule(), type)); | ||
if (param.isNull()) | ||
return clang::CanQualType(); | ||
|
||
paramTypes.push_back(param); | ||
extParamInfos.push_back(extParamInfo); | ||
} | ||
|
||
// Build the Clang function type. | ||
clang::FunctionProtoType::ExtProtoInfo defaultEPI; | ||
auto fnTy = clangCtx.getFunctionType(resultType, paramTypes, defaultEPI); | ||
clang::FunctionProtoType::ExtProtoInfo extProtoInfo; | ||
extProtoInfo.ExtParameterInfos = extParamInfos.begin(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @slavapestov -- is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes to both of these. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you know if these points are documented anywhere? I looked at the Doxygen and I couldn't find this. Also, is there some general guidelines at play here (e.g. "getFooType" always deep-copies everything in Clang) or is this a "yes, I know these particular points are true"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All AST nodes are supposed to be self-contained in both Clang and Swift (except inasmuch as they reference other AST nodes, which should themselves be self-contained). Creating an AST node should always be deep-copying any necessary arrays into trailing storage or some other associated storage. There might be exceptions for |
||
|
||
auto fnTy = clangCtx.getFunctionType(resultType, paramTypes, extProtoInfo); | ||
clang::QualType ptrTy; | ||
|
||
switch (kind) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -112,6 +112,11 @@ static void writePrologue(raw_ostream &out, ASTContext &ctx) { | |
"#else\n" | ||
"# define SWIFT_NOESCAPE\n" | ||
"#endif\n" | ||
"#if __has_attribute(ns_consumed)\n" | ||
"# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed))\n" | ||
"#else\n" | ||
"# define SWIFT_RELEASES_ARGUMENT\n" | ||
"#endif\n" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I take it it's general policy to use Swift-specific macros here (which we can just add whenever we need them) rather than the NS ones? |
||
"#if __has_attribute(warn_unused_result)\n" | ||
"# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))\n" | ||
"#else\n" | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
|
||
// RUN: %empty-directory(%t) | ||
// RUN: %build-irgen-test-overlays | ||
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-ir -disable-objc-attr-requires-foundation-module | ||
// RUN: %target-swift-frontend(mock-sdk: -sdk %S/Inputs -I %t) -primary-file %s -emit-silgen -disable-objc-attr-requires-foundation-module | %FileCheck %s | ||
|
||
// We want to test that IRGen doesn't assert on this code. SIL is the best place | ||
// to file check that the block parameter is actually +1. | ||
|
||
// REQUIRES: CPU=x86_64 | ||
// REQUIRES: objc_interop | ||
|
||
import gizmo | ||
|
||
// CHECK-LABEL: sil hidden [ossa] @$s19objc_block_consumed24passBlockWithConsumedArgyySo5GizmoC_ADtF : $@convention(thin) (@guaranteed Gizmo, @guaranteed Gizmo) -> () { | ||
func passBlockWithConsumedArg(_ g: Gizmo, _ other: Gizmo) { | ||
// CHECK: objc_method %0 : $Gizmo, #Gizmo.perform!1.foreign : (Gizmo) -> (((Gizmo?) -> ())?) -> (), $@convention(objc_method) (Optional<@convention(block) (@owned Optional<Gizmo>) -> ()>, Gizmo) -> () | ||
g.perform { other in } | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#import <Foundation/Foundation.h> | ||
|
||
static inline void takesBlockWithConsumedArg(void (^ block)(NS_RELEASES_ARGUMENT NSObject *x), NSObject *x) { | ||
block(x); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// RUN: %empty-directory(%t) | ||
// RUN: %target-build-swift %s -import-objc-header %S/Inputs/objc_block_consumed.h -o %t/main | ||
// RUN: %target-run %t/main | ||
|
||
// REQUIRES: executable_test | ||
// REQUIRES: objc_interop | ||
|
||
import Foundation | ||
import StdlibUnittest | ||
|
||
class C : NSObject { | ||
var tracked = LifetimeTracked(0) | ||
} | ||
|
||
var ObjCBlockConsumedTestSuite = TestSuite("ObjCBlockConsumed") | ||
|
||
ObjCBlockConsumedTestSuite.test("Test") { | ||
takesBlockWithConsumedArg({ arg in }, C()) | ||
} | ||
|
||
runAllTests() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@varungandhi-apple You'll need to make an analogous change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Comment for my own reference): #27479 needs to have an analogous change in
ClangTypeConverter.cpp
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, we don't need to make any changes since
visitSILFunctionType
inClangTypeConverter
is unreachable -- it should receive only AST types.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
owned
can appear in AST function parameters as well; it's in theParameterTypeFlags
.