mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
SILGen: Work around for stored property keypath components not supporting generic resilient classes
A keypath component for a stored property can take one of several forms: - The property offset is known to be constant at compile-time. This is used in the simplest cases for classes and structs. - The property offset is not constant, but can be loaded from a global. This is used for classes that require runtime resilient layout, but where the offsets do not depend on the generic context. - The property offset is not constant, and must be loaded from metadata. This is the case where the offset depends on the generic context. Here, we were only set up to load it from a fixed offset in the metadata. This works for generic structs, or generic classes where the superclass chain does not cross a resilience boundary. However, if a resilience boundary is crossed, the offset of the field offset in the metadata must itself be obtained at runtime by adding a constant to a value loaded from a global. This case is not supported by the current keypath ABI due to an oversight. I filed <rdar://problem/59777983> to track extending the ABI to handle this more elegantly in the future. Fixes <rdar://problem/59617119>.
This commit is contained in:
@@ -1353,6 +1353,24 @@ SILGenModule::canStorageUseStoredKeyPathComponent(AbstractStorageDecl *decl,
|
||||
// unowned properties.
|
||||
if (decl->getInterfaceType()->is<ReferenceStorageType>())
|
||||
return false;
|
||||
|
||||
// If the field offset depends on the generic instantiation, we have to
|
||||
// load it from metadata when instantiating the keypath component.
|
||||
//
|
||||
// However the metadata offset itself will not be fixed if the superclass
|
||||
// is resilient. Fall back to treating the property as computed in this
|
||||
// case.
|
||||
//
|
||||
// See the call to getClassFieldOffsetOffset() inside
|
||||
// emitKeyPathComponent().
|
||||
if (auto *parentClass = dyn_cast<ClassDecl>(decl->getDeclContext())) {
|
||||
if (parentClass->isGeneric()) {
|
||||
auto ancestry = parentClass->checkAncestry();
|
||||
if (ancestry.contains(AncestryFlags::ResilientOther))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the stored value would need to be reabstracted in fully opaque
|
||||
// context, then we have to treat the component as computed.
|
||||
auto componentObjTy = decl->getValueInterfaceType();
|
||||
|
||||
Reference in New Issue
Block a user