Skip to content

Commit 5ef0c4e

Browse files
authored
Merge pull request #64058 from jckarter/minimize-abi-effect-of-parameter-modifiers-b
Only mangle `borrowing`/`consuming` when they would change ABI.
2 parents 1b3fda7 + 5345e98 commit 5ef0c4e

16 files changed

+281
-138
lines changed

include/swift/AST/AnyFunctionRef.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,8 @@ class AnyFunctionRef {
304304
if (mapIntoContext)
305305
valueTy = AD->mapTypeIntoContext(valueTy);
306306
YieldTypeFlags flags(AD->getAccessorKind() == AccessorKind::Modify
307-
? ValueOwnership::InOut
308-
: ValueOwnership::Shared);
307+
? ParamSpecifier::InOut
308+
: ParamSpecifier::LegacyShared);
309309
buffer.push_back(AnyFunctionType::Yield(valueTy, flags));
310310
return buffer;
311311
}

include/swift/AST/Decl.h

Lines changed: 10 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5986,29 +5986,6 @@ class VarDecl : public AbstractStorageDecl {
59865986
}
59875987
};
59885988

5989-
/// The various spellings of ownership modifier that can be used in source.
5990-
enum class ParamSpecifier : uint8_t {
5991-
/// No explicit ownership specifier was provided. The parameter will use the
5992-
/// default ownership convention for the declaration.
5993-
Default = 0,
5994-
5995-
/// `inout`, indicating exclusive mutable access to the argument for the
5996-
/// duration of a call.
5997-
InOut = 1,
5998-
5999-
/// `borrowing`, indicating nonexclusive access to the argument for the
6000-
/// duration of a call.
6001-
Borrowing = 2,
6002-
/// `consuming`, indicating ownership transfer of the argument from caller
6003-
/// to callee.
6004-
Consuming = 3,
6005-
6006-
/// `__shared`, a legacy spelling of `borrowing`.
6007-
LegacyShared = 4,
6008-
/// `__owned`, a legacy spelling of `consuming`.
6009-
LegacyOwned = 5,
6010-
};
6011-
60125989
/// A function parameter declaration.
60135990
class ParamDecl : public VarDecl {
60145991
friend class DefaultArgumentInitContextRequest;
@@ -6374,6 +6351,16 @@ class ParamDecl : public VarDecl {
63746351
static StringRef getSpecifierSpelling(Specifier spec);
63756352
};
63766353

6354+
inline ValueOwnership
6355+
ParameterTypeFlags::getValueOwnership() const {
6356+
return ParamDecl::getValueOwnershipForSpecifier(getOwnershipSpecifier());
6357+
}
6358+
6359+
inline ValueOwnership
6360+
YieldTypeFlags::getValueOwnership() const {
6361+
return ParamDecl::getValueOwnershipForSpecifier(getOwnershipSpecifier());
6362+
}
6363+
63776364
/// Describes the kind of subscripting used in Objective-C.
63786365
enum class ObjCSubscriptKind {
63796366
/// Objective-C indexed subscripting, which is based on an integral

include/swift/AST/Types.h

Lines changed: 65 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class InOutType;
7272
class OpaqueTypeDecl;
7373
class OpenedArchetypeType;
7474
class PackType;
75+
enum class ParamSpecifier : uint8_t;
7576
class PlaceholderTypeRepr;
7677
enum class ReferenceCounting : uint8_t;
7778
enum class ResilienceExpansion : unsigned;
@@ -2069,6 +2070,29 @@ class TypeAliasType final
20692070
}
20702071
};
20712072

2073+
/// The various spellings of ownership modifier that can be used in source.
2074+
enum class ParamSpecifier : uint8_t {
2075+
/// No explicit ownership specifier was provided. The parameter will use the
2076+
/// default ownership convention for the declaration.
2077+
Default = 0,
2078+
2079+
/// `inout`, indicating exclusive mutable access to the argument for the
2080+
/// duration of a call.
2081+
InOut = 1,
2082+
2083+
/// `borrowing`, indicating nonexclusive access to the argument for the
2084+
/// duration of a call.
2085+
Borrowing = 2,
2086+
/// `consuming`, indicating ownership transfer of the argument from caller
2087+
/// to callee.
2088+
Consuming = 3,
2089+
2090+
/// `__shared`, a legacy spelling of `borrowing`.
2091+
LegacyShared = 4,
2092+
/// `__owned`, a legacy spelling of `consuming`.
2093+
LegacyOwned = 5,
2094+
};
2095+
20722096
/// Provide parameter type relevant flags, i.e. variadic, autoclosure, and
20732097
/// escaping.
20742098
class ParameterTypeFlags {
@@ -2077,8 +2101,8 @@ class ParameterTypeFlags {
20772101
Variadic = 1 << 0,
20782102
AutoClosure = 1 << 1,
20792103
NonEphemeral = 1 << 2,
2080-
OwnershipShift = 3,
2081-
Ownership = 7 << OwnershipShift,
2104+
SpecifierShift = 3,
2105+
Specifier = 7 << SpecifierShift,
20822106
NoDerivative = 1 << 6,
20832107
Isolated = 1 << 7,
20842108
CompileTimeConst = 1 << 8,
@@ -2096,19 +2120,19 @@ class ParameterTypeFlags {
20962120
}
20972121

20982122
ParameterTypeFlags(bool variadic, bool autoclosure, bool nonEphemeral,
2099-
ValueOwnership ownership, bool isolated, bool noDerivative,
2123+
ParamSpecifier specifier, bool isolated, bool noDerivative,
21002124
bool compileTimeConst)
21012125
: value((variadic ? Variadic : 0) | (autoclosure ? AutoClosure : 0) |
21022126
(nonEphemeral ? NonEphemeral : 0) |
2103-
uint8_t(ownership) << OwnershipShift |
2127+
uint8_t(specifier) << SpecifierShift |
21042128
(isolated ? Isolated : 0) |
21052129
(noDerivative ? NoDerivative : 0) |
21062130
(compileTimeConst ? CompileTimeConst : 0)){}
21072131

21082132
/// Create one from what's present in the parameter type
21092133
inline static ParameterTypeFlags
21102134
fromParameterType(Type paramTy, bool isVariadic, bool isAutoClosure,
2111-
bool isNonEphemeral, ValueOwnership ownership,
2135+
bool isNonEphemeral, ParamSpecifier ownership,
21122136
bool isolated, bool isNoDerivative,
21132137
bool compileTimeConst);
21142138

@@ -2123,18 +2147,21 @@ class ParameterTypeFlags {
21232147
bool isCompileTimeConst() const { return value.contains(CompileTimeConst); }
21242148
bool isNoDerivative() const { return value.contains(NoDerivative); }
21252149

2126-
ValueOwnership getValueOwnership() const {
2127-
return ValueOwnership((value.toRaw() & Ownership) >> OwnershipShift);
2150+
/// Get the spelling of the parameter specifier used on the parameter.
2151+
ParamSpecifier getOwnershipSpecifier() const {
2152+
return ParamSpecifier((value.toRaw() & Specifier) >> SpecifierShift);
21282153
}
21292154

2155+
ValueOwnership getValueOwnership() const;
2156+
21302157
ParameterTypeFlags withVariadic(bool variadic) const {
21312158
return ParameterTypeFlags(variadic ? value | ParameterTypeFlags::Variadic
21322159
: value - ParameterTypeFlags::Variadic);
21332160
}
21342161

21352162
ParameterTypeFlags withInOut(bool isInout) const {
2136-
return withValueOwnership(isInout ? ValueOwnership::InOut
2137-
: ValueOwnership::Default);
2163+
return withOwnershipSpecifier(isInout ? ParamSpecifier::InOut
2164+
: ParamSpecifier::Default);
21382165
}
21392166

21402167
ParameterTypeFlags withCompileTimeConst(bool isConst) const {
@@ -2143,18 +2170,18 @@ class ParameterTypeFlags {
21432170
}
21442171

21452172
ParameterTypeFlags withShared(bool isShared) const {
2146-
return withValueOwnership(isShared ? ValueOwnership::Shared
2147-
: ValueOwnership::Default);
2173+
return withOwnershipSpecifier(isShared ? ParamSpecifier::LegacyShared
2174+
: ParamSpecifier::Default);
21482175
}
21492176

21502177
ParameterTypeFlags withOwned(bool isOwned) const {
2151-
return withValueOwnership(isOwned ? ValueOwnership::Owned
2152-
: ValueOwnership::Default);
2178+
return withOwnershipSpecifier(isOwned ? ParamSpecifier::LegacyOwned
2179+
: ParamSpecifier::Default);
21532180
}
21542181

2155-
ParameterTypeFlags withValueOwnership(ValueOwnership ownership) const {
2156-
return (value - ParameterTypeFlags::Ownership)
2157-
| ParameterFlags(uint8_t(ownership) << OwnershipShift);
2182+
ParameterTypeFlags withOwnershipSpecifier(ParamSpecifier specifier) const {
2183+
return (value - ParameterTypeFlags::Specifier)
2184+
| ParameterFlags(uint8_t(specifier) << SpecifierShift);
21582185
}
21592186

21602187
ParameterTypeFlags withAutoClosure(bool isAutoClosure) const {
@@ -2217,8 +2244,8 @@ enum class ParameterFlagHandling {
22172244
class YieldTypeFlags {
22182245
enum YieldFlags : uint8_t {
22192246
None = 0,
2220-
Ownership = 7,
2221-
OwnershipShift = 0,
2247+
Specifier = 7,
2248+
SpecifierShift = 0,
22222249

22232250
NumBits = 3
22242251
};
@@ -2234,42 +2261,44 @@ class YieldTypeFlags {
22342261
return YieldTypeFlags(OptionSet<YieldFlags>(raw));
22352262
}
22362263

2237-
YieldTypeFlags(ValueOwnership ownership)
2238-
: value(uint8_t(ownership) << OwnershipShift) {}
2264+
YieldTypeFlags(ParamSpecifier specifier)
2265+
: value(uint8_t(specifier) << SpecifierShift) {}
22392266

22402267
bool isInOut() const { return getValueOwnership() == ValueOwnership::InOut; }
22412268
bool isShared() const { return getValueOwnership() == ValueOwnership::Shared;}
22422269
bool isOwned() const { return getValueOwnership() == ValueOwnership::Owned; }
22432270

2244-
ValueOwnership getValueOwnership() const {
2245-
return ValueOwnership((value.toRaw() & Ownership) >> OwnershipShift);
2271+
ParamSpecifier getOwnershipSpecifier() const {
2272+
return ParamSpecifier((value.toRaw() & Specifier) >> SpecifierShift);
22462273
}
2274+
2275+
ValueOwnership getValueOwnership() const;
22472276

22482277
YieldTypeFlags withInOut(bool isInout) const {
2249-
return withValueOwnership(isInout ? ValueOwnership::InOut
2250-
: ValueOwnership::Default);
2278+
return withOwnershipSpecifier(isInout ? ParamSpecifier::InOut
2279+
: ParamSpecifier::Default);
22512280
}
22522281

22532282
YieldTypeFlags withShared(bool isShared) const {
2254-
return withValueOwnership(isShared ? ValueOwnership::Shared
2255-
: ValueOwnership::Default);
2283+
return withOwnershipSpecifier(isShared ? ParamSpecifier::LegacyShared
2284+
: ParamSpecifier::Default);
22562285
}
22572286

22582287
YieldTypeFlags withOwned(bool isOwned) const {
2259-
return withValueOwnership(isOwned ? ValueOwnership::Owned
2260-
: ValueOwnership::Default);
2288+
return withOwnershipSpecifier(isOwned ? ParamSpecifier::LegacyOwned
2289+
: ParamSpecifier::Default);
22612290
}
22622291

2263-
YieldTypeFlags withValueOwnership(ValueOwnership ownership) const {
2264-
return (value - YieldTypeFlags::Ownership)
2265-
| YieldFlags(uint8_t(ownership) << OwnershipShift);
2292+
YieldTypeFlags withOwnershipSpecifier(ParamSpecifier ownership) const {
2293+
return (value - YieldTypeFlags::Specifier)
2294+
| YieldFlags(uint8_t(ownership) << SpecifierShift);
22662295
}
22672296

22682297
/// Return these flags interpreted as parameter flags.
22692298
ParameterTypeFlags asParamFlags() const {
22702299
return ParameterTypeFlags(/*variadic*/ false,
22712300
/*autoclosure*/ false,
2272-
/*nonEphemeral*/ false, getValueOwnership(),
2301+
/*nonEphemeral*/ false, getOwnershipSpecifier(),
22732302
/*isolated*/ false, /*noDerivative*/ false,
22742303
/*compileTimeConst*/false);
22752304
}
@@ -7087,16 +7116,16 @@ inline TupleTypeElt TupleTypeElt::getWithType(Type T) const {
70877116
/// Create one from what's present in the parameter decl and type
70887117
inline ParameterTypeFlags ParameterTypeFlags::fromParameterType(
70897118
Type paramTy, bool isVariadic, bool isAutoClosure, bool isNonEphemeral,
7090-
ValueOwnership ownership, bool isolated, bool isNoDerivative,
7119+
ParamSpecifier ownership, bool isolated, bool isNoDerivative,
70917120
bool compileTimeConst) {
70927121
// FIXME(Remove InOut): The last caller that needs this is argument
70937122
// decomposition. Start by enabling the assertion there and fixing up those
70947123
// callers, then remove this, then remove
70957124
// ParameterTypeFlags::fromParameterType entirely.
70967125
if (paramTy->is<InOutType>()) {
7097-
assert(ownership == ValueOwnership::Default ||
7098-
ownership == ValueOwnership::InOut);
7099-
ownership = ValueOwnership::InOut;
7126+
assert(ownership == ParamSpecifier::Default ||
7127+
ownership == ParamSpecifier::InOut);
7128+
ownership = ParamSpecifier::InOut;
71007129
}
71017130
return {isVariadic, isAutoClosure, isNonEphemeral, ownership, isolated,
71027131
isNoDerivative, compileTimeConst};

lib/AST/ASTContext.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3488,11 +3488,13 @@ AnyFunctionType::Param swift::computeSelfParam(AbstractFunctionDecl *AFD,
34883488
auto flags = ParameterTypeFlags().withIsolated(isIsolated);
34893489
switch (selfAccess) {
34903490
case SelfAccessKind::LegacyConsuming:
3491+
flags = flags.withOwnershipSpecifier(ParamSpecifier::LegacyOwned);
3492+
break;
34913493
case SelfAccessKind::Consuming:
3492-
flags = flags.withValueOwnership(ValueOwnership::Owned);
3494+
flags = flags.withOwnershipSpecifier(ParamSpecifier::Consuming);
34933495
break;
34943496
case SelfAccessKind::Borrowing:
3495-
flags = flags.withValueOwnership(ValueOwnership::Shared);
3497+
flags = flags.withOwnershipSpecifier(ParamSpecifier::Borrowing);
34963498
break;
34973499
case SelfAccessKind::Mutating:
34983500
flags = flags.withInOut(true);

lib/AST/ASTDemangler.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,10 @@ Type ASTBuilder::createFunctionType(
380380

381381
auto label = Ctx.getIdentifier(param.getLabel());
382382
auto flags = param.getFlags();
383-
auto ownership = flags.getValueOwnership();
383+
auto ownership =
384+
ParamDecl::getParameterSpecifierForValueOwnership(flags.getValueOwnership());
384385
auto parameterFlags = ParameterTypeFlags()
385-
.withValueOwnership(ownership)
386+
.withOwnershipSpecifier(ownership)
386387
.withVariadic(flags.isVariadic())
387388
.withAutoClosure(flags.isAutoClosure())
388389
.withNoDerivative(flags.isNoDerivative());

lib/AST/ASTMangler.cpp

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2793,10 +2793,64 @@ void ASTMangler::appendFunctionSignature(AnyFunctionType *fn,
27932793
}
27942794
}
27952795

2796+
static ParamSpecifier
2797+
getDefaultOwnership(const ValueDecl *forDecl) {
2798+
// `consuming` is the default ownership for initializers and setters.
2799+
// Everything else defaults to borrowing.
2800+
if (!forDecl) {
2801+
return ParamSpecifier::Borrowing;
2802+
}
2803+
auto forFuncDecl = dyn_cast<AbstractFunctionDecl>(forDecl);
2804+
if (!forFuncDecl) {
2805+
return ParamSpecifier::Borrowing;
2806+
}
2807+
2808+
if (isa<ConstructorDecl>(forFuncDecl)) {
2809+
return ParamSpecifier::Consuming;
2810+
} else if (auto accessor = dyn_cast<AccessorDecl>(forFuncDecl)) {
2811+
switch (accessor->getAccessorKind()) {
2812+
case AccessorKind::Modify:
2813+
case AccessorKind::Set:
2814+
return ParamSpecifier::Consuming;
2815+
default:
2816+
return ParamSpecifier::Borrowing;
2817+
}
2818+
}
2819+
2820+
return ParamSpecifier::Borrowing;
2821+
}
2822+
2823+
static ParameterTypeFlags
2824+
getParameterFlagsForMangling(ParameterTypeFlags flags,
2825+
ParamSpecifier defaultSpecifier) {
2826+
switch (auto specifier = flags.getOwnershipSpecifier()) {
2827+
// If no parameter specifier was provided, mangle as-is, because we are by
2828+
// definition using the default convention.
2829+
case ParamSpecifier::Default:
2830+
// If the legacy `__shared` or `__owned` modifier was provided, mangle as-is,
2831+
// because we need to maintain compatibility with their existing behavior.
2832+
case ParamSpecifier::LegacyShared:
2833+
case ParamSpecifier::LegacyOwned:
2834+
// `inout` should already be specified in the flags.
2835+
case ParamSpecifier::InOut:
2836+
return flags;
2837+
2838+
case ParamSpecifier::Consuming:
2839+
case ParamSpecifier::Borrowing:
2840+
// Only mangle the ownership if it diverges from the default.
2841+
if (specifier == defaultSpecifier) {
2842+
flags = flags.withOwnershipSpecifier(ParamSpecifier::Default);
2843+
}
2844+
return flags;
2845+
}
2846+
}
2847+
27962848
void ASTMangler::appendFunctionInputType(
27972849
ArrayRef<AnyFunctionType::Param> params,
27982850
GenericSignature sig,
27992851
const ValueDecl *forDecl) {
2852+
auto defaultSpecifier = getDefaultOwnership(forDecl);
2853+
28002854
switch (params.size()) {
28012855
case 0:
28022856
appendOperator("y");
@@ -2810,8 +2864,14 @@ void ASTMangler::appendFunctionInputType(
28102864
// the parameter list as a single type.
28112865
if (!param.hasLabel() && !param.isVariadic() &&
28122866
!isa<TupleType>(type.getPointer())) {
2813-
appendTypeListElement(Identifier(), type, param.getParameterFlags(),
2814-
sig, forDecl);
2867+
// Note that we pass `nullptr` as the `forDecl` argument, since the type
2868+
// of the input is no longer directly the type of the declaration, so we
2869+
// don't want it to pick up contextual behavior, such as default ownership,
2870+
// from the top-level declaration type.
2871+
appendTypeListElement(Identifier(), type,
2872+
getParameterFlagsForMangling(param.getParameterFlags(),
2873+
defaultSpecifier),
2874+
sig, nullptr);
28152875
break;
28162876
}
28172877

@@ -2823,8 +2883,14 @@ void ASTMangler::appendFunctionInputType(
28232883
default:
28242884
bool isFirstParam = true;
28252885
for (auto &param : params) {
2886+
// Note that we pass `nullptr` as the `forDecl` argument, since the type
2887+
// of the input is no longer directly the type of the declaration, so we
2888+
// don't want it to pick up contextual behavior, such as default ownership,
2889+
// from the top-level declaration type.
28262890
appendTypeListElement(Identifier(), param.getPlainType(),
2827-
param.getParameterFlags(), sig, forDecl);
2891+
getParameterFlagsForMangling(param.getParameterFlags(),
2892+
defaultSpecifier),
2893+
sig, nullptr);
28282894
appendListSeparator(isFirstParam);
28292895
}
28302896
appendOperator("t");

0 commit comments

Comments
 (0)