Skip to content

Commit 50aaad3

Browse files
authored
Merge pull request #70836 from gottesmm/transferring-parameter
[region-isolation] Add support for transferring parameters.
2 parents ae29e87 + eb57309 commit 50aaad3

30 files changed

+813
-125
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,7 @@ enum ENUM_EXTENSIBILITY_ATTR(open) BridgedAttributedTypeSpecifier : size_t {
12351235
BridgedAttributedTypeSpecifierConst,
12361236
BridgedAttributedTypeSpecifierIsolated,
12371237
BridgedAttributedTypeSpecifierResultDependsOn,
1238+
BridgedAttributedTypeSpecifierTransferring,
12381239
};
12391240

12401241
SWIFT_NAME("BridgedSimpleIdentTypeRepr.createParsed(_:loc:name:)")

include/swift/AST/Attr.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,10 @@ SIMPLE_DECL_ATTR(_noObjCBridging, NoObjCBridging,
549549
CONTEXTUAL_SIMPLE_DECL_ATTR(_resultDependsOn, ResultDependsOn,
550550
OnParam | DeclModifier | UserInaccessible | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
551551
156)
552+
CONTEXTUAL_SIMPLE_DECL_ATTR(transferring, Transferring,
553+
OnParam | DeclModifier | UserInaccessible | NotSerialized | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIStableToRemove,
554+
157)
555+
552556
#undef TYPE_ATTR
553557
#undef DECL_ATTR_ALIAS
554558
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Decl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6727,6 +6727,7 @@ class ParamDecl : public VarDecl {
67276727
return true;
67286728
case Specifier::Consuming:
67296729
case Specifier::InOut:
6730+
case Specifier::Transferring:
67306731
return false;
67316732
}
67326733
llvm_unreachable("unhandled specifier");
@@ -6744,6 +6745,7 @@ class ParamDecl : public VarDecl {
67446745
case ParamSpecifier::LegacyShared:
67456746
return ValueOwnership::Shared;
67466747
case ParamSpecifier::Consuming:
6748+
case ParamSpecifier::Transferring:
67476749
case ParamSpecifier::LegacyOwned:
67486750
return ValueOwnership::Owned;
67496751
case ParamSpecifier::Default:

include/swift/AST/DiagnosticsSIL.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,12 @@ WARNING(regionbasedisolation_transfer_yields_race_no_isolation, none,
898898
WARNING(regionbasedisolation_transfer_yields_race_with_isolation, none,
899899
"passing argument of non-sendable type %0 from %1 context to %2 context at this call site could yield a race with accesses later in this function",
900900
(Type, ActorIsolation, ActorIsolation))
901+
WARNING(regionbasedisolation_transfer_yields_race_transferring_parameter, none,
902+
"transferred value of non-Sendable type %0 into transferring parameter; later accesses could result in races",
903+
(Type))
904+
WARNING(regionbasedisolation_transfer_yields_race_stronglytransferred_binding, none,
905+
"binding of non-Sendable type %0 accessed after being transferred; later accesses could result in races",
906+
(Type))
901907
NOTE(regionbasedisolation_maybe_race, none,
902908
"access here could race", ())
903909
ERROR(regionbasedisolation_unknown_pattern, none,

include/swift/AST/Types.h

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2211,7 +2211,11 @@ enum class ParamSpecifier : uint8_t {
22112211
/// `__shared`, a legacy spelling of `borrowing`.
22122212
LegacyShared = 4,
22132213
/// `__owned`, a legacy spelling of `consuming`.
2214-
LegacyOwned = 5
2214+
LegacyOwned = 5,
2215+
2216+
/// `transferring`. Indicating the transfer of a value from one isolation
2217+
/// domain to another.
2218+
Transferring = 6,
22152219
};
22162220

22172221
/// Provide parameter type relevant flags, i.e. variadic, autoclosure, and
@@ -2228,7 +2232,8 @@ class ParameterTypeFlags {
22282232
Isolated = 1 << 7,
22292233
CompileTimeConst = 1 << 8,
22302234
ResultDependsOn = 1 << 9,
2231-
NumBits = 10
2235+
Transferring = 1 << 10,
2236+
NumBits = 11
22322237
};
22332238
OptionSet<ParameterFlags> value;
22342239
static_assert(NumBits <= 8*sizeof(OptionSet<ParameterFlags>), "overflowed");
@@ -2243,20 +2248,22 @@ class ParameterTypeFlags {
22432248

22442249
ParameterTypeFlags(bool variadic, bool autoclosure, bool nonEphemeral,
22452250
ParamSpecifier specifier, bool isolated, bool noDerivative,
2246-
bool compileTimeConst, bool hasResultDependsOn)
2251+
bool compileTimeConst, bool hasResultDependsOn,
2252+
bool isTransferring)
22472253
: value((variadic ? Variadic : 0) | (autoclosure ? AutoClosure : 0) |
22482254
(nonEphemeral ? NonEphemeral : 0) |
22492255
uint8_t(specifier) << SpecifierShift | (isolated ? Isolated : 0) |
22502256
(noDerivative ? NoDerivative : 0) |
22512257
(compileTimeConst ? CompileTimeConst : 0) |
2252-
(hasResultDependsOn ? ResultDependsOn : 0)) {}
2258+
(hasResultDependsOn ? ResultDependsOn : 0) |
2259+
(isTransferring ? Transferring : 0)) {}
22532260

22542261
/// Create one from what's present in the parameter type
22552262
inline static ParameterTypeFlags
22562263
fromParameterType(Type paramTy, bool isVariadic, bool isAutoClosure,
22572264
bool isNonEphemeral, ParamSpecifier ownership,
22582265
bool isolated, bool isNoDerivative, bool compileTimeConst,
2259-
bool hasResultDependsOn);
2266+
bool hasResultDependsOn, bool isTransferring);
22602267

22612268
bool isNone() const { return !value; }
22622269
bool isVariadic() const { return value.contains(Variadic); }
@@ -2269,6 +2276,7 @@ class ParameterTypeFlags {
22692276
bool isCompileTimeConst() const { return value.contains(CompileTimeConst); }
22702277
bool isNoDerivative() const { return value.contains(NoDerivative); }
22712278
bool hasResultDependsOn() const { return value.contains(ResultDependsOn); }
2279+
bool isTransferring() const { return value.contains(Transferring); }
22722280

22732281
/// Get the spelling of the parameter specifier used on the parameter.
22742282
ParamSpecifier getOwnershipSpecifier() const {
@@ -2331,6 +2339,12 @@ class ParameterTypeFlags {
23312339
: value - ParameterTypeFlags::NoDerivative);
23322340
}
23332341

2342+
ParameterTypeFlags withTransferring(bool withTransferring) const {
2343+
return ParameterTypeFlags(withTransferring
2344+
? value | ParameterTypeFlags::Transferring
2345+
: value - ParameterTypeFlags::Transferring);
2346+
}
2347+
23342348
bool operator ==(const ParameterTypeFlags &other) const {
23352349
return value.toRaw() == other.value.toRaw();
23362350
}
@@ -2424,7 +2438,8 @@ class YieldTypeFlags {
24242438
/*nonEphemeral*/ false, getOwnershipSpecifier(),
24252439
/*isolated*/ false, /*noDerivative*/ false,
24262440
/*compileTimeConst*/ false,
2427-
/*hasResultDependsOn*/ false);
2441+
/*hasResultDependsOn*/ false,
2442+
/*is transferring*/ false);
24282443
}
24292444

24302445
bool operator ==(const YieldTypeFlags &other) const {
@@ -4111,6 +4126,9 @@ class SILParameterInfo {
41114126
/// - If the function type is `@differentiable`, the function is
41124127
/// differentiable with respect to this parameter.
41134128
NotDifferentiable = 0x1,
4129+
4130+
/// Set if the given parameter is transferring.
4131+
Transferring = 0x2,
41144132
};
41154133

41164134
using Options = OptionSet<Flag>;
@@ -7627,7 +7645,7 @@ inline TupleTypeElt TupleTypeElt::getWithType(Type T) const {
76277645
inline ParameterTypeFlags ParameterTypeFlags::fromParameterType(
76287646
Type paramTy, bool isVariadic, bool isAutoClosure, bool isNonEphemeral,
76297647
ParamSpecifier ownership, bool isolated, bool isNoDerivative,
7630-
bool compileTimeConst, bool hasResultDependsOn) {
7648+
bool compileTimeConst, bool hasResultDependsOn, bool isTransferring) {
76317649
// FIXME(Remove InOut): The last caller that needs this is argument
76327650
// decomposition. Start by enabling the assertion there and fixing up those
76337651
// callers, then remove this, then remove
@@ -7637,8 +7655,9 @@ inline ParameterTypeFlags ParameterTypeFlags::fromParameterType(
76377655
ownership == ParamSpecifier::InOut);
76387656
ownership = ParamSpecifier::InOut;
76397657
}
7640-
return {isVariadic, isAutoClosure, isNonEphemeral, ownership,
7641-
isolated, isNoDerivative, compileTimeConst, hasResultDependsOn};
7658+
return {isVariadic, isAutoClosure, isNonEphemeral,
7659+
ownership, isolated, isNoDerivative,
7660+
compileTimeConst, hasResultDependsOn, isTransferring};
76427661
}
76437662

76447663
inline const Type *BoundGenericType::getTrailingObjectsPointer() const {

include/swift/SIL/ApplySite.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,18 @@ class FullApplySite : public ApplySite {
721721
getNumIndirectSILErrorResults());
722722
}
723723

724+
MutableArrayRef<Operand> getOperandsWithoutIndirectResults() const {
725+
return getArgumentOperands().slice(getNumIndirectSILResults() +
726+
getNumIndirectSILErrorResults());
727+
}
728+
729+
MutableArrayRef<Operand> getOperandsWithoutIndirectResultsOrSelf() const {
730+
auto ops = getOperandsWithoutIndirectResults();
731+
if (!hasSelfArgument())
732+
return ops;
733+
return ops.drop_back();
734+
}
735+
724736
InoutArgumentRange getInoutArguments() const {
725737
switch (getKind()) {
726738
case FullApplySiteKind::ApplyInst:
@@ -789,6 +801,15 @@ class FullApplySite : public ApplySite {
789801
}
790802
}
791803

804+
SILParameterInfo getArgumentParameterInfo(const Operand &oper) const {
805+
assert(!getArgumentConvention(oper).isIndirectOutParameter() &&
806+
"Can only be applied to non-out parameters");
807+
808+
// The ParameterInfo is going to be the parameter in the caller.
809+
unsigned calleeArgIndex = getCalleeArgIndex(oper);
810+
return getSubstCalleeConv().getParamInfoForSILArg(calleeArgIndex);
811+
}
812+
792813
static FullApplySite getFromOpaqueValue(void *p) { return FullApplySite(p); }
793814

794815
static bool classof(const SILInstruction *inst) {

include/swift/SIL/SILArgument.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,10 @@ class SILFunctionArgument : public SILArgument {
434434
sharedUInt32().SILFunctionArgument.hasResultDependsOn = flag;
435435
}
436436

437+
bool isTransferring() const {
438+
return getKnownParameterInfo().hasOption(SILParameterInfo::Transferring);
439+
}
440+
437441
Lifetime getLifetime() const {
438442
return getType()
439443
.getLifetime(*getFunction())

include/swift/SIL/SILInstruction.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,6 +3009,10 @@ class ApplyInstBase<Impl, Base, true>
30093009
return getArguments().slice(getNumIndirectResults());
30103010
}
30113011

3012+
MutableArrayRef<Operand> getOperandsWithoutIndirectResults() const {
3013+
return getArgumentOperands().slice(getNumIndirectResults());
3014+
}
3015+
30123016
/// Returns all `@inout` and `@inout_aliasable` arguments passed to the
30133017
/// instruction.
30143018
InoutArgumentRange getInoutArguments() const {

include/swift/SIL/SILValue.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1655,6 +1655,15 @@ namespace llvm {
16551655
enum { NumLowBitsAvailable = swift::SILValue::NumLowBitsAvailable };
16561656
};
16571657

1658+
/// A SILValue can be checked if a value is present, so we can use it with
1659+
/// dyn_cast_or_null.
1660+
template <>
1661+
struct ValueIsPresent<swift::SILValue> {
1662+
using SILValue = swift::SILValue;
1663+
using UnwrappedType = SILValue;
1664+
static inline bool isPresent(const SILValue &t) { return bool(t); }
1665+
static inline decltype(auto) unwrapValue(SILValue &t) { return t; }
1666+
};
16581667
} // end namespace llvm
16591668

16601669
#endif

include/swift/SILOptimizer/Analysis/RegionAnalysis.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ class regionanalysisimpl::TrackableValue {
254254

255255
TrackableValueState getValueState() const { return valueState; }
256256

257+
/// Returns true if this TrackableValue is an alloc_stack from a transferring
258+
/// parameter.
259+
bool isTransferringParameter() const;
260+
257261
void print(llvm::raw_ostream &os) const {
258262
os << "TrackableValue. State: ";
259263
valueState.print(os);

lib/AST/ASTBridging.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,6 +1704,10 @@ BridgedSpecifierTypeRepr BridgedSpecifierTypeRepr_createParsed(
17041704
return new (context)
17051705
OwnershipTypeRepr(baseType, ParamSpecifier::LegacyOwned, loc);
17061706
}
1707+
case BridgedAttributedTypeSpecifierTransferring: {
1708+
return new (context)
1709+
OwnershipTypeRepr(baseType, ParamSpecifier::Transferring, loc);
1710+
}
17071711
case BridgedAttributedTypeSpecifierConst: {
17081712
return new (context) CompileTimeConstTypeRepr(baseType, loc);
17091713
}

lib/AST/ASTMangler.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2875,7 +2875,8 @@ getParameterFlagsForMangling(ParameterTypeFlags flags,
28752875
// `inout` should already be specified in the flags.
28762876
case ParamSpecifier::InOut:
28772877
return flags;
2878-
2878+
2879+
case ParamSpecifier::Transferring:
28792880
case ParamSpecifier::Consuming:
28802881
case ParamSpecifier::Borrowing:
28812882
// Only mangle the ownership if it diverges from the default.

lib/AST/ASTPrinter.cpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3906,7 +3906,15 @@ static bool usesFeatureExtractConstantsFromMembers(Decl *decl) {
39063906

39073907
static bool usesFeatureBitwiseCopyable(Decl *decl) { return false; }
39083908

3909-
static bool usesFeatureTransferringArgsAndResults(Decl *decl) { return false; }
3909+
static bool usesFeatureTransferringArgsAndResults(Decl *decl) {
3910+
if (auto *pd = dyn_cast<ParamDecl>(decl))
3911+
if (pd->getSpecifier() == ParamSpecifier::Transferring)
3912+
return true;
3913+
3914+
// TODO: Results.
3915+
3916+
return false;
3917+
}
39103918

39113919
static bool usesFeaturePreconcurrencyConformances(Decl *decl) {
39123920
auto usesPreconcurrencyConformance = [&](const InheritedTypes &inherited) {
@@ -4567,6 +4575,8 @@ static void printParameterFlags(ASTPrinter &printer,
45674575
printer.printAttrName("@autoclosure ");
45684576
if (!options.excludeAttrKind(TAK_noDerivative) && flags.isNoDerivative())
45694577
printer.printAttrName("@noDerivative ");
4578+
if (flags.isTransferring())
4579+
printer.printAttrName("@transferring ");
45704580

45714581
switch (flags.getOwnershipSpecifier()) {
45724582
case ParamSpecifier::Default:
@@ -4587,6 +4597,9 @@ static void printParameterFlags(ASTPrinter &printer,
45874597
case ParamSpecifier::LegacyOwned:
45884598
printer.printKeyword("__owned", options, " ");
45894599
break;
4600+
case ParamSpecifier::Transferring:
4601+
printer.printKeyword("transferring", options, " ");
4602+
break;
45904603
}
45914604

45924605
if (flags.isIsolated())
@@ -8068,6 +8081,11 @@ void SILParameterInfo::print(ASTPrinter &Printer,
80688081
Printer << "@noDerivative ";
80698082
}
80708083

8084+
if (options.contains(SILParameterInfo::Transferring)) {
8085+
options -= SILParameterInfo::Transferring;
8086+
Printer << "@transferring ";
8087+
}
8088+
80718089
// If we did not handle a case in Options, this code was not updated
80728090
// appropriately.
80738091
assert(!bool(options) && "Code not updated for introduced option");

lib/AST/Decl.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7746,6 +7746,7 @@ void ParamDecl::setSpecifier(Specifier specifier) {
77467746
// `inout` and `consuming` parameters are locally mutable.
77477747
case ParamSpecifier::InOut:
77487748
case ParamSpecifier::Consuming:
7749+
case ParamSpecifier::Transferring:
77497750
introducer = VarDecl::Introducer::Var;
77507751
break;
77517752
}
@@ -7809,6 +7810,8 @@ StringRef ParamDecl::getSpecifierSpelling(ParamSpecifier specifier) {
78097810
return "__shared";
78107811
case ParamSpecifier::LegacyOwned:
78117812
return "__owned";
7813+
case ParamSpecifier::Transferring:
7814+
return "transferring";
78127815
}
78137816
llvm_unreachable("invalid ParamSpecifier");
78147817
}
@@ -8410,7 +8413,8 @@ AnyFunctionType::Param ParamDecl::toFunctionParam(Type type) const {
84108413
auto flags = ParameterTypeFlags::fromParameterType(
84118414
type, isVariadic(), isAutoClosure(), isNonEphemeral(), getSpecifier(),
84128415
isIsolated(), /*isNoDerivative*/ false, isCompileTimeConst(),
8413-
hasResultDependsOn());
8416+
hasResultDependsOn(),
8417+
getSpecifier() == ParamDecl::Specifier::Transferring /*is transferring*/);
84148418
return AnyFunctionType::Param(type, label, flags, internalLabel);
84158419
}
84168420

lib/Parse/ParseDecl.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5137,6 +5137,7 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51375137
Tok.isContextualKeyword("isolated") ||
51385138
Tok.isContextualKeyword("consuming") ||
51395139
Tok.isContextualKeyword("borrowing") ||
5140+
Tok.isContextualKeyword("transferring") ||
51405141
Tok.isContextualKeyword("_const") ||
51415142
Tok.isContextualKeyword("_resultDependsOn")))) {
51425143

@@ -5164,6 +5165,15 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51645165
continue;
51655166
}
51665167

5168+
// Perform an extra check for transferring. Since it is a specifier, we use
5169+
// the actual parsing logic below.
5170+
if (Tok.isContextualKeyword("transferring")) {
5171+
if (!P.Context.LangOpts.hasFeature(Feature::TransferringArgsAndResults)) {
5172+
P.diagnose(Tok, diag::requires_experimental_feature, "transferring",
5173+
false, getFeatureName(Feature::TransferringArgsAndResults));
5174+
}
5175+
}
5176+
51675177
if (SpecifierLoc.isValid()) {
51685178
P.diagnose(Tok, diag::parameter_specifier_repeated)
51695179
.fixItRemove(SpecifierLoc);
@@ -5177,6 +5187,8 @@ ParserStatus Parser::ParsedTypeAttributeList::slowParse(Parser &P) {
51775187
Specifier = ParamDecl::Specifier::LegacyOwned;
51785188
} else if (Tok.getRawText().equals("borrowing")) {
51795189
Specifier = ParamDecl::Specifier::Borrowing;
5190+
} else if (Tok.getRawText().equals("transferring")) {
5191+
Specifier = ParamDecl::Specifier::Transferring;
51805192
} else if (Tok.getRawText().equals("consuming")) {
51815193
Specifier = ParamDecl::Specifier::Consuming;
51825194
}
@@ -7539,6 +7551,8 @@ static ParserStatus parseAccessorIntroducer(Parser &P,
75397551
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Consuming);
75407552
} else if (P.Tok.isContextualKeyword("borrowing")) {
75417553
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Borrowing);
7554+
} else if (P.Tok.isContextualKeyword("transferring")) {
7555+
P.parseNewDeclAttribute(Attributes, /*AtLoc*/ {}, DAK_Transferring);
75427556
}
75437557
}
75447558

0 commit comments

Comments
 (0)