@@ -475,9 +475,14 @@ namespace {
475
475
// / Gathers information about a specific address and its uses to determine
476
476
// / definite initialization.
477
477
class ElementUseCollector {
478
+ public:
479
+ typedef SmallPtrSet<SILFunction *, 8 > FunctionSet;
480
+
481
+ private:
478
482
SILModule &Module;
479
483
const DIMemoryObjectInfo &TheMemory;
480
484
DIElementUseInfo &UseInfo;
485
+ FunctionSet &VisitedClosures;
481
486
482
487
// / IsSelfOfNonDelegatingInitializer - This is true if we're looking at the
483
488
// / top level of a 'self' variable in a non-delegating init method.
@@ -494,12 +499,15 @@ class ElementUseCollector {
494
499
495
500
public:
496
501
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
+ {}
499
507
500
508
// / This is the main entry point for the use walker. It collects uses from
501
509
// / the address and the refcount result of the allocation.
502
- void collectFrom () {
510
+ void collectFrom (SILValue V, bool collectDestroysOfContainer ) {
503
511
IsSelfOfNonDelegatingInitializer = TheMemory.isNonDelegatingInit ();
504
512
505
513
// If this is a delegating initializer, collect uses specially.
@@ -508,12 +516,16 @@ class ElementUseCollector {
508
516
assert (!TheMemory.isDerivedClassSelfOnly () &&
509
517
" Should have been handled outside of here" );
510
518
// If this is a class pointer, we need to look through ref_element_addrs.
511
- collectClassSelfUses ();
519
+ collectClassSelfUses (V );
512
520
return ;
513
521
}
514
522
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
+ }
517
529
}
518
530
519
531
void trackUse (DIMemoryUse Use) { UseInfo.trackUse (Use); }
@@ -525,7 +537,9 @@ class ElementUseCollector {
525
537
526
538
private:
527
539
void collectUses (SILValue Pointer, unsigned BaseEltNo);
528
- void collectClassSelfUses ();
540
+ bool addClosureElementUses (PartialApplyInst *pai, Operand *argUse);
541
+
542
+ void collectClassSelfUses (SILValue ClassPointer);
529
543
void collectClassSelfUses (SILValue ClassPointer, SILType MemorySILType,
530
544
llvm::SmallDenseMap<VarDecl *, unsigned > &EN);
531
545
@@ -911,9 +925,15 @@ void ElementUseCollector::collectUses(SILValue Pointer, unsigned BaseEltNo) {
911
925
continue ;
912
926
}
913
927
928
+ if (User->isDebugInstruction ())
929
+ continue ;
930
+
914
931
if (auto *PAI = dyn_cast<PartialApplyInst>(User)) {
915
932
if (onlyUsedByAssignByWrapper (PAI))
916
933
continue ;
934
+
935
+ if (BaseEltNo == 0 && addClosureElementUses (PAI, Op))
936
+ continue ;
917
937
}
918
938
919
939
// Sanitizer instrumentation is not user visible, so it should not
@@ -926,9 +946,85 @@ void ElementUseCollector::collectUses(SILValue Pointer, unsigned BaseEltNo) {
926
946
}
927
947
}
928
948
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
+
929
1025
// / collectClassSelfUses - Collect all the uses of a 'self' pointer in a class
930
1026
// / constructor. The memory object has class type.
931
- void ElementUseCollector::collectClassSelfUses () {
1027
+ void ElementUseCollector::collectClassSelfUses (SILValue ClassPointer ) {
932
1028
assert (IsSelfOfNonDelegatingInitializer &&
933
1029
TheMemory.getASTType ()->getClassOrBoundGenericClass () != nullptr );
934
1030
@@ -952,8 +1048,7 @@ void ElementUseCollector::collectClassSelfUses() {
952
1048
// If we are looking at the init method for a root class, just walk the
953
1049
// MUI use-def chain directly to find our uses.
954
1050
if (TheMemory.isRootSelf ()) {
955
- collectClassSelfUses (TheMemory.getUninitializedValue (), TheMemory.getType (),
956
- EltNumbering);
1051
+ collectClassSelfUses (ClassPointer, TheMemory.getType (), EltNumbering);
957
1052
return ;
958
1053
}
959
1054
@@ -1307,11 +1402,18 @@ void ElementUseCollector::collectClassSelfUses(
1307
1402
if (isUninitializedMetatypeInst (User))
1308
1403
continue ;
1309
1404
1405
+ if (User->isDebugInstruction ())
1406
+ continue ;
1407
+
1310
1408
// If this is a partial application of self, then this is an escape point
1311
1409
// for it.
1312
1410
if (auto *PAI = dyn_cast<PartialApplyInst>(User)) {
1313
1411
if (onlyUsedByAssignByWrapper (PAI))
1314
1412
continue ;
1413
+
1414
+ if (addClosureElementUses (PAI, Op))
1415
+ continue ;
1416
+
1315
1417
Kind = DIUseKind::Escape;
1316
1418
}
1317
1419
@@ -1709,5 +1811,8 @@ void swift::ownership::collectDIElementUsesFrom(
1709
1811
return ;
1710
1812
}
1711
1813
1712
- ElementUseCollector (MemoryInfo, UseInfo).collectFrom ();
1814
+ ElementUseCollector::FunctionSet VisitedClosures;
1815
+ ElementUseCollector collector (MemoryInfo, UseInfo, VisitedClosures);
1816
+ collector.collectFrom (MemoryInfo.getUninitializedValue (),
1817
+ /* collectDestroysOfContainer*/ true );
1713
1818
}
0 commit comments