mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[ClangImporter] Import 'swift_attr("sending")' As a Type Attribute
Previously, `__attribute__((swift_attr("sending")))` would only be
resolved when attached to declarations. This patch expands it to be
a type attribute as well, which enables it to occur in the result and
parameter positions for blocks, function pointers, and lambdas.
Resolves rdar://148435359
This commit is contained in:
@@ -726,20 +726,45 @@ namespace {
|
||||
paramQualType->getPointeeType().isConstQualified())
|
||||
paramQualType = paramQualType->getPointeeType();
|
||||
|
||||
// Mark any `sending` parameters if need be.
|
||||
ImportTypeAttrs paramAttributes;
|
||||
if (Impl.SwiftContext.LangOpts.hasFeature(Feature::SendingArgsAndResults)) {
|
||||
getConcurrencyAttrs(Impl.SwiftContext, ImportTypeKind::Parameter,
|
||||
paramAttributes, paramQualType);
|
||||
}
|
||||
|
||||
auto swiftParamTy = Impl.importTypeIgnoreIUO(
|
||||
paramQualType, paramImportKind, addImportDiagnostic,
|
||||
AllowNSUIntegerAsInt, Bridging, ImportTypeAttrs(), OTK_Optional);
|
||||
if (!swiftParamTy)
|
||||
return Type();
|
||||
|
||||
ParameterTypeFlags flags;
|
||||
flags = flags.withSending(
|
||||
paramAttributes.contains(ImportTypeAttr::Sending));
|
||||
|
||||
// FIXME(https://github.com/apple/swift/issues/45134): If we were walking TypeLocs, we could actually get parameter names.
|
||||
// The probably doesn't matter outside of a FuncDecl, which we'll have
|
||||
// to special-case, but it's an interesting bit of data loss.
|
||||
params.push_back(FunctionType::Param(swiftParamTy));
|
||||
params.emplace_back(swiftParamTy, Identifier(), flags);
|
||||
}
|
||||
|
||||
// Mark any `sending` result types if need be.
|
||||
auto extInfo = FunctionType::ExtInfo();
|
||||
ImportTypeAttrs resultAttributes;
|
||||
if (Impl.SwiftContext.LangOpts.hasFeature(Feature::SendingArgsAndResults)) {
|
||||
getConcurrencyAttrs(Impl.SwiftContext, ImportTypeKind::Result,
|
||||
resultAttributes, type->getReturnType());
|
||||
|
||||
const bool sending = resultAttributes.contains(ImportTypeAttr::Sending);
|
||||
extInfo = FunctionType::ExtInfo()
|
||||
.intoBuilder()
|
||||
.withSendingResult(sending)
|
||||
.build();
|
||||
}
|
||||
|
||||
// Form the function type.
|
||||
return FunctionType::get(params, resultTy, FunctionType::ExtInfo());
|
||||
return FunctionType::get(params, resultTy, extInfo);
|
||||
}
|
||||
|
||||
ImportResult
|
||||
@@ -1714,6 +1739,7 @@ void swift::getConcurrencyAttrs(ASTContext &SwiftContext,
|
||||
SwiftContext.LangOpts.hasFeature(Feature::SendableCompletionHandlers) &&
|
||||
importKind == ImportTypeKind::CompletionHandlerParameter;
|
||||
bool isNonSendable = false;
|
||||
bool isSending = false;
|
||||
|
||||
// Consider only immediate attributes, don't look through the typerefs
|
||||
// because they are imported separately.
|
||||
@@ -1721,10 +1747,13 @@ void swift::getConcurrencyAttrs(ASTContext &SwiftContext,
|
||||
if (isMainActorAttr(attr)) {
|
||||
isMainActor = true;
|
||||
isSendable = true; // MainActor implies Sendable
|
||||
} else if (attr->getAttribute() == "@Sendable")
|
||||
} else if (attr->getAttribute() == "@Sendable") {
|
||||
isSendable = true;
|
||||
else if (attr->getAttribute() == "@_nonSendable")
|
||||
} else if (attr->getAttribute() == "@_nonSendable") {
|
||||
isNonSendable = true;
|
||||
} else if (attr->getAttribute() == "sending") {
|
||||
isSending = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (isMainActor)
|
||||
@@ -1733,6 +1762,8 @@ void swift::getConcurrencyAttrs(ASTContext &SwiftContext,
|
||||
attrs |= ImportTypeAttr::Sendable;
|
||||
if (isNonSendable)
|
||||
attrs -= ImportTypeAttr::Sendable;
|
||||
if (isSending)
|
||||
attrs |= ImportTypeAttr::Sending;
|
||||
}
|
||||
|
||||
ImportedType ClangImporter::Implementation::importType(
|
||||
|
||||
@@ -217,6 +217,10 @@ enum class ImportTypeAttr : uint8_t {
|
||||
///
|
||||
/// This ensures that the parameter is not marked as Unmanaged.
|
||||
CFUnretainedOutParameter = 1 << 5,
|
||||
|
||||
/// Type should be imported as though declaration was marked with
|
||||
/// \c __attribute__((swift_attr("sending"))) .
|
||||
Sending = 1 << 6,
|
||||
};
|
||||
|
||||
/// Find and iterate over swift attributes embedded in the type
|
||||
|
||||
@@ -43,4 +43,7 @@ sendUserDefinedFromGlobalFunction(NonSendableCStruct other) SWIFT_SENDING;
|
||||
void sendUserDefinedIntoGlobalFunction(
|
||||
NonSendableCStruct arg SWIFT_SENDING);
|
||||
|
||||
void sendingWithCompletionHandler(void (^completion)(SWIFT_SENDING NonSendableCStruct arg));
|
||||
SWIFT_SENDING NonSendableCStruct sendingWithLazyReturn(SWIFT_SENDING NonSendableCStruct (^makeLazily)(void));
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// RUN: %target-swift-frontend -swift-version 6 -disable-availability-checking -emit-sil -o /dev/null %s -parse-as-library -enable-experimental-feature SendingArgsAndResults -verify -import-objc-header %S/Inputs/sending.h
|
||||
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk-nosource -I %t) -swift-version 6 -disable-availability-checking -emit-sil -o /dev/null %s -parse-as-library -enable-experimental-feature SendingArgsAndResults -verify -import-objc-header %S/Inputs/sending.h
|
||||
|
||||
// REQUIRES: concurrency
|
||||
// REQUIRES: swift_feature_SendingArgsAndResults
|
||||
@@ -38,3 +38,18 @@ func funcTestSendingArg() async {
|
||||
// expected-note @-1 {{'x' used after being passed as a 'sending' parameter}}
|
||||
useValue(x) // expected-note {{access can happen concurrently}}
|
||||
}
|
||||
|
||||
func funcTestSendingClosureArg() async {
|
||||
sendingWithCompletionHandler { (x: sending NonSendableCStruct) in
|
||||
sendUserDefinedIntoGlobalFunction(x) // expected-error {{sending 'x' risks causing data races}}
|
||||
// expected-note @-1 {{'x' used after being passed as a 'sending' parameter}}
|
||||
useValue(x) // expected-note {{access can happen concurrently}}
|
||||
}
|
||||
|
||||
let x = sendingWithLazyReturn { () -> sending NonSendableCStruct in
|
||||
NonSendableCStruct()
|
||||
}
|
||||
sendUserDefinedIntoGlobalFunction(x) // expected-error {{sending 'x' risks causing data races}}
|
||||
// expected-note @-1 {{'x' used after being passed as a 'sending' parameter}}
|
||||
useValue(x) // expected-note {{access can happen concurrently}}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user