[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:
Robert Widmann
2025-05-07 17:59:51 +01:00
parent 62b7a6f380
commit edcde7c55c
4 changed files with 58 additions and 5 deletions

View File

@@ -726,20 +726,45 @@ namespace {
paramQualType->getPointeeType().isConstQualified()) paramQualType->getPointeeType().isConstQualified())
paramQualType = paramQualType->getPointeeType(); 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( auto swiftParamTy = Impl.importTypeIgnoreIUO(
paramQualType, paramImportKind, addImportDiagnostic, paramQualType, paramImportKind, addImportDiagnostic,
AllowNSUIntegerAsInt, Bridging, ImportTypeAttrs(), OTK_Optional); AllowNSUIntegerAsInt, Bridging, ImportTypeAttrs(), OTK_Optional);
if (!swiftParamTy) if (!swiftParamTy)
return Type(); 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. // 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 // 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. // 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. // Form the function type.
return FunctionType::get(params, resultTy, FunctionType::ExtInfo()); return FunctionType::get(params, resultTy, extInfo);
} }
ImportResult ImportResult
@@ -1714,6 +1739,7 @@ void swift::getConcurrencyAttrs(ASTContext &SwiftContext,
SwiftContext.LangOpts.hasFeature(Feature::SendableCompletionHandlers) && SwiftContext.LangOpts.hasFeature(Feature::SendableCompletionHandlers) &&
importKind == ImportTypeKind::CompletionHandlerParameter; importKind == ImportTypeKind::CompletionHandlerParameter;
bool isNonSendable = false; bool isNonSendable = false;
bool isSending = false;
// Consider only immediate attributes, don't look through the typerefs // Consider only immediate attributes, don't look through the typerefs
// because they are imported separately. // because they are imported separately.
@@ -1721,10 +1747,13 @@ void swift::getConcurrencyAttrs(ASTContext &SwiftContext,
if (isMainActorAttr(attr)) { if (isMainActorAttr(attr)) {
isMainActor = true; isMainActor = true;
isSendable = true; // MainActor implies Sendable isSendable = true; // MainActor implies Sendable
} else if (attr->getAttribute() == "@Sendable") } else if (attr->getAttribute() == "@Sendable") {
isSendable = true; isSendable = true;
else if (attr->getAttribute() == "@_nonSendable") } else if (attr->getAttribute() == "@_nonSendable") {
isNonSendable = true; isNonSendable = true;
} else if (attr->getAttribute() == "sending") {
isSending = true;
}
}); });
if (isMainActor) if (isMainActor)
@@ -1733,6 +1762,8 @@ void swift::getConcurrencyAttrs(ASTContext &SwiftContext,
attrs |= ImportTypeAttr::Sendable; attrs |= ImportTypeAttr::Sendable;
if (isNonSendable) if (isNonSendable)
attrs -= ImportTypeAttr::Sendable; attrs -= ImportTypeAttr::Sendable;
if (isSending)
attrs |= ImportTypeAttr::Sending;
} }
ImportedType ClangImporter::Implementation::importType( ImportedType ClangImporter::Implementation::importType(

View File

@@ -217,6 +217,10 @@ enum class ImportTypeAttr : uint8_t {
/// ///
/// This ensures that the parameter is not marked as Unmanaged. /// This ensures that the parameter is not marked as Unmanaged.
CFUnretainedOutParameter = 1 << 5, 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 /// Find and iterate over swift attributes embedded in the type

View File

@@ -43,4 +43,7 @@ sendUserDefinedFromGlobalFunction(NonSendableCStruct other) SWIFT_SENDING;
void sendUserDefinedIntoGlobalFunction( void sendUserDefinedIntoGlobalFunction(
NonSendableCStruct arg SWIFT_SENDING); 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 #pragma clang assume_nonnull end

View File

@@ -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: concurrency
// REQUIRES: swift_feature_SendingArgsAndResults // REQUIRES: swift_feature_SendingArgsAndResults
@@ -38,3 +38,18 @@ func funcTestSendingArg() async {
// expected-note @-1 {{'x' used after being passed as a 'sending' parameter}} // expected-note @-1 {{'x' used after being passed as a 'sending' parameter}}
useValue(x) // expected-note {{access can happen concurrently}} 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}}
}