@@ -243,23 +243,18 @@ namespace {
243
243
244
244
// If this failed with a dependency, infer the current metadata state
245
245
// and return.
246
- if (dependency.Value ) {
247
- return { inferStateForMetadata (metadata),
248
- dependency.State , dependency.Value };
246
+ if (dependency) {
247
+ return { inferStateForMetadata (metadata), dependency };
249
248
}
250
249
}
251
250
252
251
// Check for transitive completeness.
253
- auto dependency =
254
- checkTransitiveCompleteness (metadata, description);
255
- if (dependency.Value ) {
256
- return { PrivateMetadataState::NonTransitiveComplete,
257
- dependency.State , dependency.Value };
252
+ if (auto dependency = checkTransitiveCompleteness (metadata, description)){
253
+ return { PrivateMetadataState::NonTransitiveComplete, dependency };
258
254
}
259
255
260
256
// We're done.
261
- return { PrivateMetadataState::Complete,
262
- MetadataState::Complete, nullptr };
257
+ return { PrivateMetadataState::Complete, MetadataDependency () };
263
258
}
264
259
};
265
260
} // end anonymous namespace
@@ -3333,24 +3328,24 @@ static Result performOnMetadataCache(const Metadata *metadata,
3333
3328
}
3334
3329
3335
3330
bool swift::addToMetadataQueue (MetadataCompletionQueueEntry *queueEntry,
3336
- const Metadata *dependency,
3337
- MetadataState dependencyRequirement) {
3331
+ MetadataDependency dependency) {
3338
3332
struct EnqueueCallbacks {
3339
3333
MetadataCompletionQueueEntry *QueueEntry;
3334
+ MetadataDependency Dependency;
3340
3335
3341
3336
bool forGenericMetadata (const Metadata *metadata,
3342
3337
const TypeContextDescriptor *description,
3343
3338
GenericMetadataCache &cache,
3344
3339
MetadataCacheKey key) && {
3345
- return cache.enqueue (key, QueueEntry);
3340
+ return cache.enqueue (key, QueueEntry, Dependency );
3346
3341
}
3347
3342
3348
3343
bool forOtherMetadata (const Metadata *metadata) && {
3349
3344
swift_runtime_unreachable (" metadata should always be complete" );
3350
3345
}
3351
- } callbacks = { queueEntry };
3346
+ } callbacks = { queueEntry, dependency };
3352
3347
3353
- return performOnMetadataCache<bool >(dependency, std::move (callbacks));
3348
+ return performOnMetadataCache<bool >(dependency. Value , std::move (callbacks));
3354
3349
}
3355
3350
3356
3351
void swift::resumeMetadataCompletion (MetadataCompletionQueueEntry *queueEntry) {
@@ -3553,6 +3548,114 @@ checkTransitiveCompleteness(const Metadata *initialType,
3553
3548
return { nullptr , MetadataState::Complete };
3554
3549
}
3555
3550
3551
+ // / Diagnose a metadata dependency cycle.
3552
+ LLVM_ATTRIBUTE_NORETURN
3553
+ static void diagnoseMetadataDependencyCycle (const Metadata *start,
3554
+ ArrayRef<MetadataDependency> links){
3555
+ assert (start == links.back ().Value );
3556
+
3557
+ std::string diagnostic =
3558
+ " runtime error: unresolvable type metadata dependency cycle detected\n " ;
3559
+ diagnostic += nameForMetadata (start);
3560
+
3561
+ for (auto &link : links) {
3562
+ // If the diagnostic gets too large, just cut it short.
3563
+ if (diagnostic.size () >= 128 * 1024 ) {
3564
+ diagnostic += " \n (limiting diagnostic text at 128KB)" ;
3565
+ break ;
3566
+ }
3567
+
3568
+ diagnostic += " \n depends on " ;
3569
+
3570
+ switch (link.Requirement ) {
3571
+ case MetadataState::Complete:
3572
+ diagnostic += " transitive completion of " ;
3573
+ break ;
3574
+ case MetadataState::NonTransitiveComplete:
3575
+ diagnostic += " completion of " ;
3576
+ break ;
3577
+ case MetadataState::LayoutComplete:
3578
+ diagnostic += " layout of " ;
3579
+ break ;
3580
+ case MetadataState::Abstract:
3581
+ diagnostic += " <corruption> of " ;
3582
+ break ;
3583
+ }
3584
+
3585
+ diagnostic += nameForMetadata (link.Value );
3586
+ }
3587
+
3588
+ diagnostic += " \n Aborting!\n " ;
3589
+
3590
+ if (_swift_shouldReportFatalErrorsToDebugger ()) {
3591
+ #pragma GCC diagnostic push
3592
+ #pragma GCC diagnostic ignored "-Wc99-extensions"
3593
+ RuntimeErrorDetails details = {
3594
+ .version = RuntimeErrorDetails::currentVersion,
3595
+ .errorType = " type-metadata-cycle" ,
3596
+ .currentStackDescription = " fetching metadata" , // TODO?
3597
+ .framesToSkip = 1 , // skip out to the check function
3598
+ .memoryAddress = start
3599
+ // TODO: describe the cycle using notes instead of one huge message?
3600
+ };
3601
+ #pragma GCC diagnostic pop
3602
+
3603
+ _swift_reportToDebugger (RuntimeErrorFlagFatal, diagnostic.c_str (),
3604
+ &details);
3605
+ }
3606
+
3607
+ fatalError (0 , diagnostic.c_str ());
3608
+ }
3609
+
3610
+ // / Check whether the given metadata dependency is satisfied, and if not,
3611
+ // / return its current dependency, if one exists.
3612
+ static MetadataDependency
3613
+ checkMetadataDependency (MetadataDependency dependency) {
3614
+ struct IsIncompleteCallbacks {
3615
+ MetadataState Requirement;
3616
+ MetadataDependency forGenericMetadata (const Metadata *type,
3617
+ const TypeContextDescriptor *desc,
3618
+ GenericMetadataCache &cache,
3619
+ MetadataCacheKey key) && {
3620
+ return cache.checkDependency (key, Requirement);
3621
+ }
3622
+
3623
+ MetadataDependency forOtherMetadata (const Metadata *type) && {
3624
+ return MetadataDependency ();
3625
+ }
3626
+ } callbacks = { dependency.Requirement };
3627
+
3628
+ return performOnMetadataCache<MetadataDependency>(dependency.Value ,
3629
+ std::move (callbacks));
3630
+ }
3631
+
3632
+ // / Check for an unbreakable metadata-dependency cycle.
3633
+ void swift::checkMetadataDependencyCycle (const Metadata *startMetadata,
3634
+ MetadataDependency firstLink,
3635
+ MetadataDependency secondLink) {
3636
+ std::vector<MetadataDependency> links;
3637
+ auto checkNewLink = [&](MetadataDependency newLink) {
3638
+ links.push_back (newLink);
3639
+ if (newLink.Value == startMetadata)
3640
+ diagnoseMetadataDependencyCycle (startMetadata, links);
3641
+ for (auto i = links.begin (), e = links.end () - 1 ; i != e; ++i) {
3642
+ if (i->Value == newLink.Value ) {
3643
+ auto next = i + 1 ;
3644
+ diagnoseMetadataDependencyCycle (i->Value ,
3645
+ llvm::makeArrayRef (&*next, links.end () - next));
3646
+ }
3647
+ }
3648
+ };
3649
+
3650
+ checkNewLink (firstLink);
3651
+ checkNewLink (secondLink);
3652
+ while (true ) {
3653
+ auto newLink = checkMetadataDependency (links.back ());
3654
+ if (!newLink) return ;
3655
+ checkNewLink (newLink);
3656
+ }
3657
+ }
3658
+
3556
3659
/* **************************************************************************/
3557
3660
/* ** Allocator implementation **********************************************/
3558
3661
/* **************************************************************************/
0 commit comments