Skip to content

Commit 5c4406b

Browse files
committed
Add an @_addressableForDependencies type attribute.
This attribute makes it so that a parameter of the annotated type, as well as any type structurally containing that type as a field, becomes passed as if `@_addressable` if the return value of the function has a dependency on the parameter. This allows nonescapable values to take interior pointers into such types.
1 parent 5bcb696 commit 5c4406b

18 files changed

+408
-54
lines changed

include/swift/AST/DeclAttr.def

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -524,18 +524,22 @@ DECL_ATTR(lifetime, Lifetime,
524524
161)
525525

526526
SIMPLE_DECL_ATTR(_addressableSelf, AddressableSelf,
527-
OnAccessor | OnConstructor | OnFunc | OnSubscript | ABIBreakingToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove | UserInaccessible,
527+
OnAccessor | OnConstructor | OnFunc | OnSubscript | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UserInaccessible,
528528
162)
529529

530+
SIMPLE_DECL_ATTR(_addressableForDependencies, AddressableForDependencies,
531+
OnNominalType | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove | UserInaccessible,
532+
163)
533+
530534
DECL_ATTR(safe, Safe,
531535
OnAbstractFunction | OnSubscript | OnVar | OnMacro | OnNominalType |
532536
OnExtension | OnTypeAlias | OnImport | UserInaccessible |
533537
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIStableToRemove,
534-
163)
538+
164)
535539

536540
DECL_ATTR(abi, ABI,
537541
OnAbstractFunction | OnVar /* will eventually add types */ | LongAttribute | ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
538-
164)
542+
165)
539543
DECL_ATTR_FEATURE_REQUIREMENT(ABI, ABIAttribute)
540544

541545
LAST_DECL_ATTR(ABI)

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,10 @@ ERROR(addressable_not_enabled,none,
313313
"@_addressable is an experimental feature", ())
314314
ERROR(addressableSelf_not_on_method,none,
315315
"@_addressableSelf cannot be applied to non-member declarations", ())
316+
ERROR(addressable_types_not_enabled,none,
317+
"@_addressableForDependencies is an experimental feature", ())
318+
ERROR(class_cannot_be_addressable_for_dependencies,none,
319+
"a class cannot be @_addressableForDependencies", ())
316320

317321
ERROR(unsupported_closure_attr,none,
318322
"%select{attribute |}0 '%1' is not supported on a closure",

include/swift/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ EXPERIMENTAL_FEATURE(CoroutineAccessorsAllocateInCallee, false)
434434
EXPERIMENTAL_FEATURE(GenerateForceToMainActorThunks, false)
435435

436436
EXPERIMENTAL_FEATURE(AddressableParameters, true)
437+
EXPERIMENTAL_FEATURE(AddressableTypes, true)
437438

438439
/// Allow the @abi attribute.
439440
SUPPRESSIBLE_EXPERIMENTAL_FEATURE(ABIAttribute, true)

include/swift/SIL/AbstractionPattern.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,6 +1558,16 @@ class AbstractionPattern {
15581558
/// for one of its parameters.
15591559
ParameterTypeFlags getFunctionParamFlags(unsigned index) const;
15601560

1561+
/// Given that the value being abstracted is a function type, return whether
1562+
/// the indicated parameter should be treated as addressable, meaning
1563+
/// calls should preserve the in-memory address of the argument for as
1564+
/// long as any dependencies may live.
1565+
///
1566+
/// This may be true either because the type is structurally addressable for
1567+
/// dependencies, or because it was explicitly marked as `@_addressable`
1568+
/// in its declaration.
1569+
bool isFunctionParamAddressable(TypeConverter &TC, unsigned index) const;
1570+
15611571
/// Given that the value being abstracted is a function type, and that
15621572
/// this is not an opaque abstraction pattern, return the number of
15631573
/// parameters in the pattern.

include/swift/SIL/TypeLowering.h

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,17 @@ enum HasPack_t : bool {
176176
HasPack = true,
177177
};
178178

179+
/// Is the type addressable-for-dependencies?
180+
///
181+
/// Values of an addressable-for-dependency type are passed indirectly into
182+
/// functions that specify a return value lifetime dependency on the value.
183+
/// This allows the dependent value to safely contain pointers to the in-memory
184+
/// representation of the source of the dependency.
185+
enum IsAddressableForDependencies_t : bool {
186+
IsNotAddressableForDependencies = false,
187+
IsAddressableForDependencies = true,
188+
};
189+
179190
/// Extended type information used by SIL.
180191
class TypeLowering {
181192
public:
@@ -184,15 +195,16 @@ class TypeLowering {
184195
//
185196
// clang-format off
186197
enum : unsigned {
187-
NonTrivialFlag = 1 << 0,
188-
NonFixedABIFlag = 1 << 1,
189-
AddressOnlyFlag = 1 << 2,
190-
ResilientFlag = 1 << 3,
191-
TypeExpansionSensitiveFlag = 1 << 4,
192-
InfiniteFlag = 1 << 5,
193-
HasRawPointerFlag = 1 << 6,
194-
LexicalFlag = 1 << 7,
195-
HasPackFlag = 1 << 8,
198+
NonTrivialFlag = 1 << 0,
199+
NonFixedABIFlag = 1 << 1,
200+
AddressOnlyFlag = 1 << 2,
201+
ResilientFlag = 1 << 3,
202+
TypeExpansionSensitiveFlag = 1 << 4,
203+
InfiniteFlag = 1 << 5,
204+
HasRawPointerFlag = 1 << 6,
205+
LexicalFlag = 1 << 7,
206+
HasPackFlag = 1 << 8,
207+
AddressableForDependenciesFlag = 1 << 9,
196208
};
197209
// clang-format on
198210

@@ -209,15 +221,17 @@ class TypeLowering {
209221
IsTypeExpansionSensitive_t isTypeExpansionSensitive =
210222
IsNotTypeExpansionSensitive,
211223
HasRawPointer_t hasRawPointer = DoesNotHaveRawPointer,
212-
IsLexical_t isLexical = IsNotLexical, HasPack_t hasPack = HasNoPack)
224+
IsLexical_t isLexical = IsNotLexical, HasPack_t hasPack = HasNoPack,
225+
IsAddressableForDependencies_t isAFD = IsAddressableForDependencies)
213226
: Flags((isTrivial ? 0U : NonTrivialFlag) |
214227
(isFixedABI ? 0U : NonFixedABIFlag) |
215228
(isAddressOnly ? AddressOnlyFlag : 0U) |
216229
(isResilient ? ResilientFlag : 0U) |
217230
(isTypeExpansionSensitive ? TypeExpansionSensitiveFlag : 0U) |
218231
(hasRawPointer ? HasRawPointerFlag : 0U) |
219232
(isLexical ? LexicalFlag : 0U) |
220-
(hasPack ? HasPackFlag : 0U)) {}
233+
(hasPack ? HasPackFlag : 0U) |
234+
(isAFD ? AddressableForDependenciesFlag : 0U)) {}
221235

222236
constexpr bool operator==(RecursiveProperties p) const {
223237
return Flags == p.Flags;
@@ -227,6 +241,12 @@ class TypeLowering {
227241
return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient};
228242
}
229243

244+
static constexpr RecursiveProperties forTrivialOpaque() {
245+
return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient,
246+
IsNotTypeExpansionSensitive, HasRawPointer, IsNotLexical,
247+
HasNoPack, IsAddressableForDependencies};
248+
}
249+
230250
static constexpr RecursiveProperties forRawPointer() {
231251
return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsNotResilient,
232252
IsNotTypeExpansionSensitive, HasRawPointer};
@@ -239,11 +259,14 @@ class TypeLowering {
239259

240260
static constexpr RecursiveProperties forOpaque() {
241261
return {IsNotTrivial, IsNotFixedABI, IsAddressOnly, IsNotResilient,
242-
IsNotTypeExpansionSensitive, DoesNotHaveRawPointer, IsLexical, HasNoPack};
262+
IsNotTypeExpansionSensitive, HasRawPointer, IsLexical,
263+
HasNoPack, IsAddressableForDependencies};
243264
}
244265

245266
static constexpr RecursiveProperties forResilient() {
246-
return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsResilient};
267+
return {IsTrivial, IsFixedABI, IsNotAddressOnly, IsResilient,
268+
IsNotTypeExpansionSensitive, HasRawPointer, IsNotLexical,
269+
HasNoPack, IsAddressableForDependencies};
247270
}
248271

249272
void addSubobject(RecursiveProperties other) {
@@ -278,6 +301,10 @@ class TypeLowering {
278301
HasPack_t isOrContainsPack() const {
279302
return HasPack_t((Flags & HasPackFlag) != 0);
280303
}
304+
IsAddressableForDependencies_t isAddressableForDependencies() const {
305+
return IsAddressableForDependencies_t(
306+
(Flags & AddressableForDependenciesFlag) != 0);
307+
}
281308

282309
void setNonTrivial() { Flags |= NonTrivialFlag; }
283310
void setIsOrContainsRawPointer() { Flags |= HasRawPointerFlag; }
@@ -294,6 +321,9 @@ class TypeLowering {
294321
Flags = (Flags & ~LexicalFlag) | (isLexical ? LexicalFlag : 0);
295322
}
296323
void setHasPack() { Flags |= HasPackFlag; }
324+
void setAddressableForDependencies() {
325+
Flags |= AddressableForDependenciesFlag;
326+
}
297327
};
298328

299329
private:

lib/AST/ASTDumper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3760,6 +3760,7 @@ class PrintAttribute : public AttributeVisitor<PrintAttribute, void, StringRef>,
37603760

37613761
TRIVIAL_ATTR_PRINTER(Actor, actor)
37623762
TRIVIAL_ATTR_PRINTER(AddressableSelf, _addressableSelf)
3763+
TRIVIAL_ATTR_PRINTER(AddressableForDependencies, _addressableForDependencies)
37633764
TRIVIAL_ATTR_PRINTER(AlwaysEmitConformanceMetadata,
37643765
always_emit_conformance_metadata)
37653766
TRIVIAL_ATTR_PRINTER(AlwaysEmitIntoClient, always_emit_into_client)

lib/AST/FeatureSet.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,14 @@ static bool usesFeatureAddressableParameters(Decl *d) {
308308
return false;
309309
}
310310

311+
static bool usesFeatureAddressableTypes(Decl *d) {
312+
if (d->getAttrs().hasAttribute<AddressableForDependenciesAttr>()) {
313+
return true;
314+
}
315+
316+
return false;
317+
}
318+
311319
UNINTERESTING_FEATURE(IsolatedAny2)
312320
UNINTERESTING_FEATURE(GlobalActorIsolatedTypesUsability)
313321
UNINTERESTING_FEATURE(ObjCImplementation)

lib/ASTGen/Sources/ASTGen/DeclAttrs.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ extension ASTGenVisitor {
191191

192192
// Simple attributes.
193193
case .addressableSelf,
194+
.addressableForDependencies,
194195
.alwaysEmitConformanceMetadata,
195196
.alwaysEmitIntoClient,
196197
.atReasync,

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,6 +1649,72 @@ AbstractionPattern::getFunctionParamFlags(unsigned index) const {
16491649
.getParameterFlags();
16501650
}
16511651

1652+
bool
1653+
AbstractionPattern::isFunctionParamAddressable(TypeConverter &TC,
1654+
unsigned index) const {
1655+
switch (getKind()) {
1656+
case Kind::Invalid:
1657+
case Kind::Tuple:
1658+
llvm_unreachable("not any kind of function!");
1659+
case Kind::Opaque:
1660+
case Kind::OpaqueFunction:
1661+
case Kind::OpaqueDerivativeFunction:
1662+
// If the function abstraction pattern is completely opaque, assume we
1663+
// may need to preserve the address for dependencies.
1664+
return true;
1665+
1666+
case Kind::ClangType:
1667+
case Kind::ObjCCompletionHandlerArgumentsType:
1668+
case Kind::CurriedObjCMethodType:
1669+
case Kind::PartialCurriedObjCMethodType:
1670+
case Kind::ObjCMethodType:
1671+
case Kind::CFunctionAsMethodType:
1672+
case Kind::CurriedCFunctionAsMethodType:
1673+
case Kind::PartialCurriedCFunctionAsMethodType:
1674+
case Kind::CXXMethodType:
1675+
case Kind::CurriedCXXMethodType:
1676+
case Kind::PartialCurriedCXXMethodType:
1677+
case Kind::Type:
1678+
case Kind::Discard: {
1679+
auto type = getType();
1680+
1681+
if (type->isTypeParameter() || type->is<ArchetypeType>()) {
1682+
// If the function abstraction pattern is completely opaque, assume we
1683+
// may need to preserve the address for dependencies.
1684+
return true;
1685+
}
1686+
1687+
auto fnTy = cast<AnyFunctionType>(getType());
1688+
1689+
// The parameter might directly be marked addressable.
1690+
if (fnTy.getParams()[index].getParameterFlags().isAddressable()) {
1691+
return true;
1692+
}
1693+
1694+
// The parameter could be of a type that is addressable for dependencies,
1695+
// in which case it becomes addressable when a return has a scoped
1696+
// dependency on it.
1697+
for (auto &dep : fnTy->getLifetimeDependencies()) {
1698+
auto scoped = dep.getScopeIndices();
1699+
if (!scoped) {
1700+
continue;
1701+
}
1702+
1703+
if (scoped->contains(index)) {
1704+
auto paramTy = getFunctionParamType(index);
1705+
1706+
return TC.getTypeLowering(paramTy, paramTy.getType(),
1707+
TypeExpansionContext::minimal())
1708+
.getRecursiveProperties().isAddressableForDependencies();
1709+
}
1710+
}
1711+
1712+
return false;
1713+
}
1714+
}
1715+
llvm_unreachable("bad kind");
1716+
}
1717+
16521718
unsigned AbstractionPattern::getNumFunctionParams() const {
16531719
return cast<AnyFunctionType>(getType()).getParams().size();
16541720
}

0 commit comments

Comments
 (0)