@@ -476,14 +476,15 @@ namespace {
476
476
477
477
AvailabilitySet getLivenessAtInst (SILInstruction *Inst, unsigned FirstElt,
478
478
unsigned NumElts);
479
+ int getAnyUninitializedMemberAtInst (SILInstruction *Inst, unsigned FirstElt,
480
+ unsigned NumElts);
481
+
479
482
DIKind getSelfConsumedAtInst (SILInstruction *Inst);
480
483
481
484
bool isInitializedAtUse (const DIMemoryUse &Use,
482
485
bool *SuperInitDone = nullptr ,
483
486
bool *FailedSelfUse = nullptr );
484
487
485
- bool hasUninitializedMemberAtInst (SILInstruction *Inst, unsigned FirstElt,
486
- unsigned NumElts);
487
488
488
489
void handleStoreUse (unsigned UseID);
489
490
void handleInOutUse (const DIMemoryUse &Use);
@@ -674,20 +675,14 @@ std::string LifetimeChecker::getUninitElementName(const DIMemoryUse &Use) {
674
675
// the query, to get a bitmask of exactly which elements are uninitialized.
675
676
// In a multi-element query, the first element may already be defined and
676
677
// we want to point to the second one.
677
- AvailabilitySet Liveness =
678
- getLivenessAtInst (Use.Inst , Use.FirstElement , Use.NumElements );
679
-
680
- unsigned FirstUndefElement = Use.FirstElement ;
681
- while (Liveness.get (FirstUndefElement) == DIKind::Yes) {
682
- ++FirstUndefElement;
683
- assert (FirstUndefElement != Use.FirstElement +Use.NumElements &&
684
- " No undef elements found?" );
685
- }
686
-
678
+ unsigned firstUndefElement =
679
+ getAnyUninitializedMemberAtInst (Use.Inst , Use.FirstElement ,Use.NumElements );
680
+ assert (firstUndefElement != ~0U && " No undef elements found?" );
681
+
687
682
// Verify that it isn't the super.init marker that failed. The client should
688
683
// handle this, not pass it down to diagnoseInitError.
689
684
assert ((!TheMemory.isDerivedClassSelf () ||
690
- FirstUndefElement != TheMemory.NumElements -1 ) &&
685
+ firstUndefElement != TheMemory.NumElements -1 ) &&
691
686
" super.init failure not handled in the right place" );
692
687
693
688
// If the definition is a declaration, try to reconstruct a name and
@@ -698,7 +693,7 @@ std::string LifetimeChecker::getUninitElementName(const DIMemoryUse &Use) {
698
693
// an error about "v" instead of "v.0" when "v" has tuple type and the whole
699
694
// thing is accessed inappropriately.
700
695
std::string Name;
701
- TheMemory.getPathStringToElement (FirstUndefElement , Name);
696
+ TheMemory.getPathStringToElement (firstUndefElement , Name);
702
697
703
698
return Name;
704
699
}
@@ -1331,24 +1326,14 @@ void LifetimeChecker::handleLoadUseFailure(const DIMemoryUse &Use,
1331
1326
(unsigned )TheMemory.isDelegatingInit ());
1332
1327
return ;
1333
1328
}
1334
-
1335
- SILLocation Loc = Inst->getLoc ();
1336
1329
1337
- // Try to find the return location
1338
- auto TermLoc = Inst->getParent ()->getTerminator ()->getLoc ();
1339
- if (TermLoc.getKind () == SILLocation::ReturnKind) {
1340
- Loc = TermLoc;
1341
- }
1342
-
1343
1330
// If this is a load with a single user that is a return (and optionally a
1344
1331
// retain_value for non-trivial structs/enums), then this is a return in the
1345
1332
// enum/struct init case, and we haven't stored to self. Emit a specific
1346
1333
// diagnostic.
1347
1334
if (auto *LI = dyn_cast<LoadInst>(Inst)) {
1348
1335
bool hasReturnUse = false , hasUnknownUses = false ;
1349
1336
1350
- auto *LoadBB = LI->getParent ();
1351
-
1352
1337
for (auto LoadUse : LI->getUses ()) {
1353
1338
auto *User = LoadUse->getUser ();
1354
1339
@@ -1362,18 +1347,6 @@ void LifetimeChecker::handleLoadUseFailure(const DIMemoryUse &Use,
1362
1347
1363
1348
if (auto *EI = dyn_cast<EnumInst>(User))
1364
1349
if (isFailableInitReturnUseOfEnum (EI)) {
1365
- // Try to find the return location
1366
- for (auto Pred : LoadBB->getPreds ()) {
1367
- auto *TI = Pred->getTerminator ();
1368
- auto TermLoc = TI->getLoc ();
1369
-
1370
- // Check if this is an early return with uninitialized members
1371
- if (TermLoc.getKind () == SILLocation::ReturnKind &&
1372
- hasUninitializedMemberAtInst (TI, Use.FirstElement ,
1373
- Use.NumElements ))
1374
- Loc = TermLoc;
1375
- }
1376
-
1377
1350
hasReturnUse = true ;
1378
1351
continue ;
1379
1352
}
@@ -1382,16 +1355,41 @@ void LifetimeChecker::handleLoadUseFailure(const DIMemoryUse &Use,
1382
1355
break ;
1383
1356
}
1384
1357
1358
+ // Okay, this load is part of a return sequence, diagnose it specially.
1385
1359
if (hasReturnUse && !hasUnknownUses) {
1360
+ // The load is probably part of the common epilog for the function, try to
1361
+ // find a more useful source location than the syntactic end of the
1362
+ // function.
1363
+ SILLocation returnLoc = Inst->getLoc ();
1364
+ auto TermLoc = Inst->getParent ()->getTerminator ()->getLoc ();
1365
+ if (TermLoc.getKind () == SILLocation::ReturnKind) {
1366
+ // Function has a single return that got merged into the epilog block.
1367
+ returnLoc = TermLoc;
1368
+ } else {
1369
+ // Otherwise, there are multiple paths to the epilog block, scan its
1370
+ // predecessors to see if there are any where the value is unavailable.
1371
+ // If so, we can use its location information for more precision.
1372
+ for (auto pred : LI->getParent ()->getPreds ()) {
1373
+ auto *TI = pred->getTerminator ();
1374
+ // Check if this is an early return with uninitialized members.
1375
+ if (TI->getLoc ().getKind () == SILLocation::ReturnKind &&
1376
+ getAnyUninitializedMemberAtInst (TI, Use.FirstElement ,
1377
+ Use.NumElements ) != -1 )
1378
+ returnLoc = TI->getLoc ();
1379
+ }
1380
+ }
1381
+
1386
1382
if (TheMemory.isEnumInitSelf ()) {
1387
1383
if (!shouldEmitError (Inst)) return ;
1388
- diagnose (Module, Loc ,
1384
+ diagnose (Module, returnLoc ,
1389
1385
diag::return_from_init_without_initing_self);
1390
1386
return ;
1391
- } else if (TheMemory.isAnyInitSelf () && !TheMemory.isClassInitSelf () &&
1387
+ }
1388
+
1389
+ if (TheMemory.isAnyInitSelf () && !TheMemory.isClassInitSelf () &&
1392
1390
!TheMemory.isDelegatingInit ()) {
1393
1391
if (!shouldEmitError (Inst)) return ;
1394
- diagnose (Module, Loc ,
1392
+ diagnose (Module, returnLoc ,
1395
1393
diag::return_from_init_without_initing_stored_properties);
1396
1394
noteUninitializedMembers (Use);
1397
1395
return ;
@@ -1746,8 +1744,7 @@ void LifetimeChecker::processNonTrivialRelease(unsigned ReleaseID) {
1746
1744
// destruction.
1747
1745
assert (isa<StrongReleaseInst>(Release) || isa<DestroyAddrInst>(Release));
1748
1746
1749
- AvailabilitySet Availability =
1750
- getLivenessAtInst (Release, 0 , TheMemory.NumElements );
1747
+ auto Availability = getLivenessAtInst (Release, 0 , TheMemory.NumElements );
1751
1748
DIKind SelfConsumed =
1752
1749
getSelfConsumedAtInst (Release);
1753
1750
@@ -2407,6 +2404,23 @@ getLivenessAtInst(SILInstruction *Inst, unsigned FirstElt, unsigned NumElts) {
2407
2404
return Result;
2408
2405
}
2409
2406
2407
+ // / If any of the elements in the specified range are uninitialized at the
2408
+ // / specified instruction, return the first element that is uninitialized. If
2409
+ // / they are all initialized, return -1.
2410
+ int LifetimeChecker::getAnyUninitializedMemberAtInst (SILInstruction *Inst,
2411
+ unsigned FirstElt,
2412
+ unsigned NumElts) {
2413
+ // Determine the liveness states of the elements that we care about.
2414
+ auto Liveness = getLivenessAtInst (Inst, FirstElt, NumElts);
2415
+
2416
+ // Find unintialized member.
2417
+ for (unsigned i = FirstElt, e = i+NumElts; i != e; ++i)
2418
+ if (Liveness.get (i) != DIKind::Yes)
2419
+ return i;
2420
+
2421
+ return -1 ;
2422
+ }
2423
+
2410
2424
// / getSelfConsumedAtInst - Compute the liveness state for any number of tuple
2411
2425
// / elements at the specified instruction. The elements are returned as an
2412
2426
// / AvailabilitySet. Elements outside of the range specified may not be
@@ -2471,21 +2485,6 @@ bool LifetimeChecker::isInitializedAtUse(const DIMemoryUse &Use,
2471
2485
return true ;
2472
2486
}
2473
2487
2474
- bool LifetimeChecker::hasUninitializedMemberAtInst (SILInstruction *Inst,
2475
- unsigned FirstElt,
2476
- unsigned NumElts) {
2477
- // Determine the liveness states of the elements that we care about.
2478
- AvailabilitySet Liveness =
2479
- getLivenessAtInst (Inst, FirstElt, NumElts);
2480
-
2481
- // Find unintialized member
2482
- for (unsigned i = FirstElt, e = i+NumElts;
2483
- i != e; ++i)
2484
- if (Liveness.get (i) != DIKind::Yes)
2485
- return true ;
2486
-
2487
- return false ;
2488
- }
2489
2488
2490
2489
2491
2490
0 commit comments