@@ -475,9 +475,14 @@ namespace {
475475// / Gathers information about a specific address and its uses to determine
476476// / definite initialization.
477477class ElementUseCollector {
478+ public:
479+ typedef SmallPtrSet<SILFunction *, 8 > FunctionSet;
480+
481+ private:
478482 SILModule &Module;
479483 const DIMemoryObjectInfo &TheMemory;
480484 DIElementUseInfo &UseInfo;
485+ FunctionSet &VisitedClosures;
481486
482487 // / IsSelfOfNonDelegatingInitializer - This is true if we're looking at the
483488 // / top level of a 'self' variable in a non-delegating init method.
@@ -494,12 +499,15 @@ class ElementUseCollector {
494499
495500public:
496501 ElementUseCollector (const DIMemoryObjectInfo &TheMemory,
497- DIElementUseInfo &UseInfo)
498- : Module(TheMemory.getModule()), TheMemory(TheMemory), UseInfo(UseInfo) {}
502+ DIElementUseInfo &UseInfo,
503+ FunctionSet &visitedClosures)
504+ : Module(TheMemory.getModule()), TheMemory(TheMemory), UseInfo(UseInfo),
505+ VisitedClosures (visitedClosures)
506+ {}
499507
500508 // / This is the main entry point for the use walker. It collects uses from
501509 // / the address and the refcount result of the allocation.
502- void collectFrom () {
510+ void collectFrom (SILValue V, bool collectDestroysOfContainer ) {
503511 IsSelfOfNonDelegatingInitializer = TheMemory.isNonDelegatingInit ();
504512
505513 // If this is a delegating initializer, collect uses specially.
@@ -508,12 +516,16 @@ class ElementUseCollector {
508516 assert (!TheMemory.isDerivedClassSelfOnly () &&
509517 " Should have been handled outside of here" );
510518 // If this is a class pointer, we need to look through ref_element_addrs.
511- collectClassSelfUses ();
519+ collectClassSelfUses (V );
512520 return ;
513521 }
514522
515- collectUses (TheMemory.getUninitializedValue (), 0 );
516- gatherDestroysOfContainer (TheMemory, UseInfo);
523+ collectUses (V, 0 );
524+ if (collectDestroysOfContainer) {
525+ assert (V == TheMemory.getUninitializedValue () &&
526+ " can only gather destroys of root value" );
527+ gatherDestroysOfContainer (TheMemory, UseInfo);
528+ }
517529 }
518530
519531 void trackUse (DIMemoryUse Use) { UseInfo.trackUse (Use); }
@@ -525,7 +537,9 @@ class ElementUseCollector {
525537
526538private:
527539 void collectUses (SILValue Pointer, unsigned BaseEltNo);
528- void collectClassSelfUses ();
540+ bool addClosureElementUses (PartialApplyInst *pai, Operand *argUse);
541+
542+ void collectClassSelfUses (SILValue ClassPointer);
529543 void collectClassSelfUses (SILValue ClassPointer, SILType MemorySILType,
530544 llvm::SmallDenseMap<VarDecl *, unsigned > &EN);
531545
@@ -911,9 +925,15 @@ void ElementUseCollector::collectUses(SILValue Pointer, unsigned BaseEltNo) {
911925 continue ;
912926 }
913927
928+ if (User->isDebugInstruction ())
929+ continue ;
930+
914931 if (auto *PAI = dyn_cast<PartialApplyInst>(User)) {
915932 if (onlyUsedByAssignByWrapper (PAI))
916933 continue ;
934+
935+ if (BaseEltNo == 0 && addClosureElementUses (PAI, Op))
936+ continue ;
917937 }
918938
919939 // Sanitizer instrumentation is not user visible, so it should not
@@ -926,9 +946,85 @@ void ElementUseCollector::collectUses(SILValue Pointer, unsigned BaseEltNo) {
926946 }
927947}
928948
949+ // / Add all used elements of an implicit closure, which is capturing 'self'.
950+ // /
951+ // / We want to correctly handle implicit closures in initializers, e.g. with
952+ // / boolean operators:
953+ // / \code
954+ // / init() {
955+ // / bool_member1 = false
956+ // / bool_member2 = false || bool_member1 // implicit closure
957+ // / }
958+ // / \endcode
959+ // /
960+ // / The implicit closure ('bool_member1' at the RHS of the || operator) captures
961+ // / the whole self, but only uses 'bool_member1'.
962+ // / If we would add the whole captured 'self' as use, we would get a
963+ // / "'self.bool_member2' not initialized" error at the partial_apply.
964+ // / Therefore we look into the body of the closure and only add the actually
965+ // / used members.
966+ bool ElementUseCollector::addClosureElementUses (PartialApplyInst *pai,
967+ Operand *argUse) {
968+ SILFunction *callee = pai->getReferencedFunctionOrNull ();
969+ if (!callee)
970+ return false ;
971+
972+ // Implicit closures are "transparent", which means they are always inlined.
973+ // It would probably also work to handle non-transparent closures (e.g.
974+ // explicit closures). But if the closure is not inlined we could end up
975+ // passing a partially initialized self to the closure function. Although it
976+ // would probably not cause any real problems, an `@in_guaranteed` argument
977+ // (the captured 'self') is assumed to be fully initialized in SIL.
978+ if (!callee->isTransparent ())
979+ return false ;
980+
981+ // Implicit closures are only partial-applied once and there cannot be a
982+ // recursive cycle of implicit closures.
983+ // Nevertheless such a scenario is theoretically possible in SIL. To be on the
984+ // safe side, check for cycles.
985+ if (!VisitedClosures.insert (callee).second )
986+ return false ;
987+
988+ unsigned argIndex = ApplySite (pai).getCalleeArgIndex (*argUse);
989+ SILArgument *arg = callee->getArgument (argIndex);
990+
991+ // Bail if arg is not the original 'self' object, but e.g. a projected member.
992+ assert (TheMemory.getType ().isObject ());
993+ if (arg->getType ().getObjectType () != TheMemory.getType ())
994+ return false ;
995+
996+ DIElementUseInfo ArgUseInfo;
997+ ElementUseCollector collector (TheMemory, ArgUseInfo, VisitedClosures);
998+ collector.collectFrom (arg, /* collectDestroysOfContainer*/ false );
999+
1000+ if (!ArgUseInfo.Releases .empty () || !ArgUseInfo.StoresToSelf .empty ())
1001+ return false ;
1002+
1003+ for (const DIMemoryUse &use : ArgUseInfo.Uses ) {
1004+ // Only handle loads and escapes. Implicit closures will not have stores or
1005+ // store-like uses, anyway.
1006+ // Also, as we don't do a flow-sensitive analysis of the callee, we cannot
1007+ // handle stores, because we don't know if they are unconditional or not.
1008+ switch (use.Kind ) {
1009+ case DIUseKind::Load:
1010+ case DIUseKind::Escape:
1011+ case DIUseKind::InOutArgument:
1012+ break ;
1013+ default :
1014+ return false ;
1015+ }
1016+ }
1017+
1018+ // Track all uses of the closure.
1019+ for (const DIMemoryUse &use : ArgUseInfo.Uses ) {
1020+ trackUse (DIMemoryUse (pai, use.Kind , use.FirstElement , use.NumElements ));
1021+ }
1022+ return true ;
1023+ }
1024+
9291025// / collectClassSelfUses - Collect all the uses of a 'self' pointer in a class
9301026// / constructor. The memory object has class type.
931- void ElementUseCollector::collectClassSelfUses () {
1027+ void ElementUseCollector::collectClassSelfUses (SILValue ClassPointer ) {
9321028 assert (IsSelfOfNonDelegatingInitializer &&
9331029 TheMemory.getASTType ()->getClassOrBoundGenericClass () != nullptr );
9341030
@@ -952,8 +1048,7 @@ void ElementUseCollector::collectClassSelfUses() {
9521048 // If we are looking at the init method for a root class, just walk the
9531049 // MUI use-def chain directly to find our uses.
9541050 if (TheMemory.isRootSelf ()) {
955- collectClassSelfUses (TheMemory.getUninitializedValue (), TheMemory.getType (),
956- EltNumbering);
1051+ collectClassSelfUses (ClassPointer, TheMemory.getType (), EltNumbering);
9571052 return ;
9581053 }
9591054
@@ -1307,11 +1402,18 @@ void ElementUseCollector::collectClassSelfUses(
13071402 if (isUninitializedMetatypeInst (User))
13081403 continue ;
13091404
1405+ if (User->isDebugInstruction ())
1406+ continue ;
1407+
13101408 // If this is a partial application of self, then this is an escape point
13111409 // for it.
13121410 if (auto *PAI = dyn_cast<PartialApplyInst>(User)) {
13131411 if (onlyUsedByAssignByWrapper (PAI))
13141412 continue ;
1413+
1414+ if (addClosureElementUses (PAI, Op))
1415+ continue ;
1416+
13151417 Kind = DIUseKind::Escape;
13161418 }
13171419
@@ -1709,5 +1811,8 @@ void swift::ownership::collectDIElementUsesFrom(
17091811 return ;
17101812 }
17111813
1712- ElementUseCollector (MemoryInfo, UseInfo).collectFrom ();
1814+ ElementUseCollector::FunctionSet VisitedClosures;
1815+ ElementUseCollector collector (MemoryInfo, UseInfo, VisitedClosures);
1816+ collector.collectFrom (MemoryInfo.getUninitializedValue (),
1817+ /* collectDestroysOfContainer*/ true );
17131818}
0 commit comments