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->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(
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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}}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user