@@ -252,7 +252,7 @@ void LifetimeDependenceInfo::getConcatenatedData(
252252}
253253
254254class LifetimeDependenceChecker {
255- AbstractFunctionDecl *afd ;
255+ ValueDecl *decl ;
256256
257257 DeclContext *dc;
258258 ASTContext &ctx;
@@ -273,9 +273,8 @@ class LifetimeDependenceChecker {
273273 bool performedDiagnostics = false ;
274274
275275public:
276- LifetimeDependenceChecker (AbstractFunctionDecl *afd):
277- afd (afd), dc(afd->getDeclContext ()), ctx(dc->getASTContext ())
278- {
276+ LifetimeDependenceChecker (AbstractFunctionDecl *afd)
277+ : decl(afd), dc(afd->getDeclContext ()), ctx(dc->getASTContext ()) {
279278 auto resultTypeRepr = afd->getResultTypeRepr ();
280279 returnLoc = resultTypeRepr ? resultTypeRepr->getLoc () : afd->getLoc ();
281280
@@ -287,18 +286,25 @@ class LifetimeDependenceChecker {
287286 }
288287 }
289288
289+ LifetimeDependenceChecker (EnumElementDecl *eed)
290+ : decl(eed), dc(eed->getDeclContext ()), ctx(dc->getASTContext ()) {
291+ auto *paramList = eed->getParameterList ();
292+ resultIndex = paramList ? eed->getParameterList ()->size () + 1 : 1 ;
293+ }
294+
290295 std::optional<llvm::ArrayRef<LifetimeDependenceInfo>>
291296 currentDependencies () const {
292297 if (lifetimeDependencies.empty ()) {
293298 return std::nullopt ;
294299 }
295- return afd ->getASTContext ().AllocateCopy (lifetimeDependencies);
300+ return decl ->getASTContext ().AllocateCopy (lifetimeDependencies);
296301 }
297302
298303 std::optional<llvm::ArrayRef<LifetimeDependenceInfo>> checkFuncDecl () {
299- assert (isa<FuncDecl>(afd ) || isa<ConstructorDecl>(afd ));
304+ assert (isa<FuncDecl>(decl ) || isa<ConstructorDecl>(decl ));
300305 assert (lifetimeDependencies.empty ());
301306
307+ auto *afd = cast<AbstractFunctionDecl>(decl);
302308 // Handle Builtins first because, even though Builtins require
303309 // LifetimeDependence, we don't force the experimental feature
304310 // to be enabled when importing the Builtin module.
@@ -351,6 +357,52 @@ class LifetimeDependenceChecker {
351357 return currentDependencies ();
352358 }
353359
360+ std::optional<llvm::ArrayRef<LifetimeDependenceInfo>> checkEnumElementDecl () {
361+ auto *eed = cast<EnumElementDecl>(decl);
362+ auto *parentEnum = eed->getParentEnum ();
363+ auto enumType =
364+ parentEnum->mapTypeIntoContext (parentEnum->getDeclaredInterfaceType ());
365+
366+ // Add early bailout for imported enums.
367+ if (parentEnum->hasClangNode ()) {
368+ return std::nullopt ;
369+ }
370+
371+ // Escapable enum, bailout.
372+ if (!isDiagnosedNonEscapable (enumType)) {
373+ return std::nullopt ;
374+ }
375+ auto *params = eed->getParameterList ();
376+ // No payload, bailout.
377+ if (!params) {
378+ return std::nullopt ;
379+ }
380+
381+ auto resultIndex = params->size () + /* selfType*/ 1 ;
382+ auto capacity = resultIndex + 1 ;
383+ SmallBitVector inheritIndices (capacity);
384+ SmallVector<LifetimeDependenceInfo, 1 > lifetimeDependencies;
385+
386+ // Add all indices of ~Escapable parameters as lifetime dependence sources.
387+ for (size_t i = 0 ; i < params->size (); i++) {
388+ auto paramType = params->get (i)->getTypeInContext ();
389+ if (!isDiagnosedNonEscapable (paramType)) {
390+ continue ;
391+ }
392+ inheritIndices.set (i);
393+ }
394+ if (inheritIndices.none ()) {
395+ return std::nullopt ;
396+ }
397+ auto lifetimeDependenceInfo = LifetimeDependenceInfo (
398+ IndexSubset::get (eed->getASTContext (), inheritIndices), nullptr ,
399+ resultIndex,
400+ /* isImmortal*/ false );
401+ lifetimeDependencies.push_back (lifetimeDependenceInfo);
402+
403+ return eed->getASTContext ().AllocateCopy (lifetimeDependencies);
404+ }
405+
354406protected:
355407 template <typename ...ArgTypes>
356408 InFlightDiagnostic diagnose (
@@ -367,9 +419,7 @@ class LifetimeDependenceChecker {
367419 return ctx.Diags .diagnose (decl, Diagnostic (id, std::move (args)...));
368420 }
369421
370- bool isInit () const {
371- return isa<ConstructorDecl>(afd);
372- }
422+ bool isInit () const { return isa<ConstructorDecl>(decl); }
373423
374424 // For initializers, the implicit self parameter is ignored and instead shows
375425 // up as the result type.
@@ -381,11 +431,13 @@ class LifetimeDependenceChecker {
381431 // the extra formal self parameter, a dependency targeting the formal result
382432 // index would incorrectly target the SIL metatype parameter.
383433 bool hasImplicitSelfParam () const {
434+ auto *afd = cast<AbstractFunctionDecl>(decl);
384435 return !isInit () && afd->hasImplicitSelfDecl ();
385436 }
386437
387438 // In SIL, implicit initializers and accessors become explicit.
388439 bool isImplicitOrSIL () const {
440+ auto *afd = cast<AbstractFunctionDecl>(decl);
389441 if (afd->isImplicit ()) {
390442 return true ;
391443 }
@@ -404,7 +456,7 @@ class LifetimeDependenceChecker {
404456 bool isInterfaceFile () const {
405457 // TODO: remove this check once all compilers that are rev-locked to the
406458 // stdlib print the 'copy' dependence kind in the interface (Aug '25)
407- if (auto *sf = afd ->getParentSourceFile ()) {
459+ if (auto *sf = decl-> getDeclContext () ->getParentSourceFile ()) {
408460 if (sf->Kind == SourceFileKind::Interface) {
409461 return true ;
410462 }
@@ -419,6 +471,7 @@ class LifetimeDependenceChecker {
419471 }
420472
421473 std::string diagnosticQualifier () const {
474+ auto *afd = cast<AbstractFunctionDecl>(decl);
422475 if (afd->isImplicit ()) {
423476 if (isInit ()) {
424477 return " an implicit initializer" ;
@@ -463,6 +516,7 @@ class LifetimeDependenceChecker {
463516 // initializers, the inout self parameter is actually considered the result
464517 // type so is not handled here.
465518 void diagnoseMissingSelfDependencies (DiagID diagID) {
519+ auto *afd = cast<AbstractFunctionDecl>(decl);
466520 if (!hasImplicitSelfParam ()) {
467521 return ;
468522 }
@@ -483,6 +537,7 @@ class LifetimeDependenceChecker {
483537 }
484538
485539 void diagnoseMissingInoutDependencies (DiagID diagID) {
540+ auto *afd = cast<AbstractFunctionDecl>(decl);
486541 unsigned paramIndex = 0 ;
487542 for (auto *param : *afd->getParameters ()) {
488543 SWIFT_DEFER { paramIndex++; };
@@ -529,6 +584,7 @@ class LifetimeDependenceChecker {
529584
530585 bool isCompatibleWithOwnership (LifetimeDependenceKind kind, Type type,
531586 ValueOwnership ownership) const {
587+ auto *afd = cast<AbstractFunctionDecl>(decl);
532588 if (kind == LifetimeDependenceKind::Inherit) {
533589 return true ;
534590 }
@@ -569,6 +625,7 @@ class LifetimeDependenceChecker {
569625 };
570626
571627 TargetDeps createDeps (unsigned targetIndex) {
628+ auto *afd = cast<AbstractFunctionDecl>(decl);
572629 unsigned capacity = afd->hasImplicitSelfDecl ()
573630 ? (afd->getParameters ()->size () + 1 )
574631 : afd->getParameters ()->size ();
@@ -599,6 +656,7 @@ class LifetimeDependenceChecker {
599656 }
600657
601658 Type getResultOrYield () const {
659+ auto *afd = cast<AbstractFunctionDecl>(decl);
602660 if (auto *accessor = dyn_cast<AccessorDecl>(afd)) {
603661 if (accessor->isCoroutine ()) {
604662 auto yieldTyInContext = accessor->mapTypeIntoContext (
@@ -618,11 +676,12 @@ class LifetimeDependenceChecker {
618676
619677 std::optional<LifetimeDependenceKind>
620678 getDependenceKindFromDescriptor (LifetimeDescriptor descriptor,
621- ParamDecl *decl) {
679+ ParamDecl *paramDecl) {
680+ auto *afd = cast<AbstractFunctionDecl>(decl);
622681 auto loc = descriptor.getLoc ();
623- auto type = decl ->getTypeInContext ();
682+ auto type = paramDecl ->getTypeInContext ();
624683 auto parsedLifetimeKind = descriptor.getParsedLifetimeDependenceKind ();
625- auto ownership = decl ->getValueOwnership ();
684+ auto ownership = paramDecl ->getValueOwnership ();
626685 auto loweredOwnership = ownership != ValueOwnership::Default
627686 ? ownership
628687 : getLoweredOwnership (afd);
@@ -704,6 +763,7 @@ class LifetimeDependenceChecker {
704763 // Finds the ParamDecl* and its index from a LifetimeDescriptor
705764 std::optional<std::pair<ParamDecl *, unsigned >>
706765 getParamDeclFromDescriptor (LifetimeDescriptor descriptor) {
766+ auto *afd = cast<AbstractFunctionDecl>(decl);
707767 switch (descriptor.getDescriptorKind ()) {
708768 case LifetimeDescriptor::DescriptorKind::Named: {
709769 unsigned paramIndex = 0 ;
@@ -752,6 +812,7 @@ class LifetimeDependenceChecker {
752812 }
753813
754814 std::optional<ArrayRef<LifetimeDependenceInfo>> checkAttribute () {
815+ auto *afd = cast<AbstractFunctionDecl>(decl);
755816 SmallVector<LifetimeDependenceInfo, 1 > lifetimeDependencies;
756817 llvm::SmallSet<unsigned , 1 > lifetimeDependentTargets;
757818 auto lifetimeAttrs = afd->getAttrs ().getAttributes <LifetimeAttr>();
@@ -776,6 +837,7 @@ class LifetimeDependenceChecker {
776837
777838 std::optional<LifetimeDependenceInfo>
778839 checkAttributeEntry (LifetimeEntry *entry) {
840+ auto *afd = cast<AbstractFunctionDecl>(decl);
779841 auto capacity = afd->hasImplicitSelfDecl ()
780842 ? (afd->getParameters ()->size () + 1 )
781843 : afd->getParameters ()->size ();
@@ -897,6 +959,7 @@ class LifetimeDependenceChecker {
897959 // / If the current function is a mutating method and 'self' is non-Escapable,
898960 // / return 'self's ParamDecl.
899961 bool isMutatingNonEscapableSelf () {
962+ auto *afd = cast<AbstractFunctionDecl>(decl);
900963 if (!hasImplicitSelfParam ())
901964 return false ;
902965
@@ -914,6 +977,7 @@ class LifetimeDependenceChecker {
914977 // Infer method dependence of result on self for
915978 // methods, getters, and _modify accessors.
916979 void inferNonEscapableResultOnSelf () {
980+ auto *afd = cast<AbstractFunctionDecl>(decl);
917981 Type selfTypeInContext = dc->getSelfTypeInContext ();
918982 if (selfTypeInContext->hasError ()) {
919983 return ;
@@ -980,6 +1044,7 @@ class LifetimeDependenceChecker {
9801044 // stored property (for getters or initializers).
9811045 std::optional<LifetimeDependenceKind>
9821046 inferLifetimeDependenceKind (Type sourceType, ValueOwnership ownership) {
1047+ auto *afd = cast<AbstractFunctionDecl>(decl);
9831048 if (!sourceType->isEscapable ()) {
9841049 return LifetimeDependenceKind::Inherit;
9851050 }
@@ -1003,6 +1068,7 @@ class LifetimeDependenceChecker {
10031068 // to an implicit setter, because the implementation is simply an assignment
10041069 // to stored property.
10051070 void inferImplicitInit () {
1071+ auto *afd = cast<AbstractFunctionDecl>(decl);
10061072 if (afd->getParameters ()->size () == 0 ) {
10071073 // Empty ~Escapable types can be implicitly initialized without any
10081074 // dependencies. In SIL, implicit initializers become explicit. Set
@@ -1042,6 +1108,7 @@ class LifetimeDependenceChecker {
10421108 // inference if any exist, infer scoped dependency, or infer no
10431109 // dependency. Implicit setters for Escapable properties are not inferred.
10441110 void inferNonEscapableResultOnParam () {
1111+ auto *afd = cast<AbstractFunctionDecl>(decl);
10451112 // This is only called when there is no 'self' argument that can be the
10461113 // source of a dependence.
10471114 assert (!hasImplicitSelfParam ());
@@ -1091,6 +1158,7 @@ class LifetimeDependenceChecker {
10911158 // Lazy inference for .swiftinterface backward compatibility and
10921159 // experimentation. Inference cases can be added but not removed.
10931160 void lazillyInferNonEscapableResultOnParam () {
1161+ auto *afd = cast<AbstractFunctionDecl>(decl);
10941162 std::optional<unsigned > candidateParamIndex;
10951163 std::optional<LifetimeDependenceKind> candidateLifetimeKind;
10961164 unsigned paramIndex = 0 ;
@@ -1137,6 +1205,7 @@ class LifetimeDependenceChecker {
11371205 // Infer a mutating 'self' dependency when 'self' is non-Escapable and the
11381206 // result is 'void'.
11391207 void inferMutatingSelf () {
1208+ auto *afd = cast<AbstractFunctionDecl>(decl);
11401209 if (!isMutatingNonEscapableSelf ()) {
11411210 return ;
11421211 }
@@ -1166,7 +1235,7 @@ class LifetimeDependenceChecker {
11661235 // Infer dependence for an accessor whose non-escapable result depends on
11671236 // self. This includes _read and _modify.
11681237 void inferAccessor (AccessorDecl *accessor, Type selfTypeInContext) {
1169- // Explicit accessors require explicit lifetime dependencies.
1238+ auto *afd = cast<AbstractFunctionDecl>(decl);
11701239 if (!isImplicitOrSIL () && !useLazyInference ()) {
11711240 return ;
11721241 }
@@ -1205,6 +1274,7 @@ class LifetimeDependenceChecker {
12051274 break ;
12061275 case AccessorKind::Set: {
12071276 const unsigned newValIdx = 0 ;
1277+ auto *afd = cast<AbstractFunctionDecl>(decl);
12081278 auto *param = afd->getParameters ()->get (newValIdx);
12091279 Type paramTypeInContext =
12101280 afd->mapTypeIntoContext (param->getInterfaceType ());
@@ -1285,6 +1355,7 @@ class LifetimeDependenceChecker {
12851355 }
12861356 }
12871357 }
1358+ auto *afd = cast<AbstractFunctionDecl>(decl);
12881359 // Either a Get or Modify without any wrapped accessor. Handle these like a
12891360 // read of the stored property.
12901361 return inferLifetimeDependenceKind (
@@ -1315,6 +1386,7 @@ class LifetimeDependenceChecker {
13151386 // Do not issue any diagnostics. This inference is triggered even when the
13161387 // feature is disabled!
13171388 void inferInoutParams () {
1389+ auto *afd = cast<AbstractFunctionDecl>(decl);
13181390 if (isMutatingNonEscapableSelf ()) {
13191391 return ;
13201392 }
@@ -1347,6 +1419,7 @@ class LifetimeDependenceChecker {
13471419 }
13481420
13491421 void inferUnambiguousInoutParams () {
1422+ auto *afd = cast<AbstractFunctionDecl>(decl);
13501423 if (afd->getParameters ()->size () != 1 ) {
13511424 return ;
13521425 }
@@ -1364,6 +1437,7 @@ class LifetimeDependenceChecker {
13641437 }
13651438
13661439 void inferBuiltin () {
1440+ auto *afd = cast<AbstractFunctionDecl>(decl);
13671441 // Normal inout parameter inference works for most generic Builtins.
13681442 inferUnambiguousInoutParams ();
13691443 if (!lifetimeDependencies.empty ()) {
@@ -1397,8 +1471,12 @@ class LifetimeDependenceChecker {
13971471};
13981472
13991473std::optional<llvm::ArrayRef<LifetimeDependenceInfo>>
1400- LifetimeDependenceInfo::get (AbstractFunctionDecl *afd) {
1401- return LifetimeDependenceChecker (afd).checkFuncDecl ();
1474+ LifetimeDependenceInfo::get (ValueDecl *decl) {
1475+ if (auto *afd = dyn_cast<AbstractFunctionDecl>(decl)) {
1476+ return LifetimeDependenceChecker (afd).checkFuncDecl ();
1477+ }
1478+ auto *eed = cast<EnumElementDecl>(decl);
1479+ return LifetimeDependenceChecker (eed).checkEnumElementDecl ();
14021480}
14031481
14041482// This implements the logic for SIL type descriptors similar to source-level
0 commit comments