Skip to content

Commit 50731eb

Browse files
committed
Sema: Fix inheritance of @requires_stored_property_inits
Previously we would copy this attribute from a superclass to the subclass when validating a subclass. However, this is only correct if the superclass is always guaranteed to have been validated before the subclass. Indeed, it appears this assumption is no longer true, so we would sometimes lose track of the attribute, which would result in SILGen failing to emit the ivar initializer entry point. Instead, check for the attribute as part of the superclass walk in checkAncestry(), ensuring the result is always up to date, correct, and cached. As a follow-up, we should also convert checkAncestry() into a request, but I'm not doing that here to keep the fix short. Fixes <rdar://problem/50845438>.
1 parent 98db6e1 commit 50731eb

File tree

9 files changed

+44
-31
lines changed

9 files changed

+44
-31
lines changed

include/swift/AST/Decl.h

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -566,11 +566,7 @@ class alignas(1 << DeclAlignInBits) Decl {
566566
NumRequirementsInSignature : 16
567567
);
568568

569-
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+2+1+2+1+6+1+1+1,
570-
/// Whether this class requires all of its instance variables to
571-
/// have in-class initializers.
572-
RequiresStoredPropertyInits : 1,
573-
569+
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 2+1+2+1+7+1+1+1,
574570
/// The stage of the inheritance circularity check for this class.
575571
Circularity : 2,
576572

@@ -588,7 +584,7 @@ class alignas(1 << DeclAlignInBits) Decl {
588584
HasDestructorDecl : 1,
589585

590586
/// Information about the class's ancestry.
591-
Ancestry : 6,
587+
Ancestry : 7,
592588

593589
/// Whether we have computed the above field or not.
594590
AncestryComputed : 1,
@@ -3740,6 +3736,9 @@ enum class AncestryFlags : uint8_t {
37403736

37413737
/// The class or one of its superclasses is imported from Clang.
37423738
ClangImported = (1<<5),
3739+
3740+
/// The class or one of its superclasses requires stored property initializers.
3741+
RequiresStoredPropertyInits = (1<<6),
37433742
};
37443743

37453744
/// Return type of ClassDecl::checkAncestry(). Describes a set of interesting
@@ -3837,14 +3836,8 @@ class ClassDecl final : public NominalTypeDecl {
38373836

38383837
//// Whether this class requires all of its stored properties to
38393838
//// have initializers in the class definition.
3840-
bool requiresStoredPropertyInits() const {
3841-
return Bits.ClassDecl.RequiresStoredPropertyInits;
3842-
}
3843-
3844-
/// Set whether this class requires all of its stored properties to
3845-
/// have initializers in the class definition.
3846-
void setRequiresStoredPropertyInits(bool requiresInits) {
3847-
Bits.ClassDecl.RequiresStoredPropertyInits = requiresInits;
3839+
bool requiresStoredPropertyInits() const {
3840+
return checkAncestry(AncestryFlags::RequiresStoredPropertyInits);
38483841
}
38493842

38503843
/// \see getForeignClassKind

include/swift/Serialization/ModuleFormat.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ const uint16_t SWIFTMODULE_VERSION_MAJOR = 0;
5252
/// describe what change you made. The content of this comment isn't important;
5353
/// it just ensures a conflict if two people change the module format.
5454
/// Don't worry about adhering to the 80-column limit for this line.
55-
const uint16_t SWIFTMODULE_VERSION_MINOR = 498; // dependency types for protocols
55+
const uint16_t SWIFTMODULE_VERSION_MINOR = 499; // remove 'requires stored property inits'
5656

5757
using DeclIDField = BCFixed<31>;
5858

@@ -976,7 +976,6 @@ namespace decls_block {
976976
DeclContextIDField, // context decl
977977
BCFixed<1>, // implicit?
978978
BCFixed<1>, // explicitly objc?
979-
BCFixed<1>, // requires stored property initial values?
980979
BCFixed<1>, // inherits convenience initializers from its superclass?
981980
GenericEnvironmentIDField, // generic environment
982981
TypeIDField, // superclass

lib/AST/Decl.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3679,7 +3679,6 @@ ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
36793679
ClassLoc(ClassLoc) {
36803680
Bits.ClassDecl.Circularity
36813681
= static_cast<unsigned>(CircularityCheck::Unchecked);
3682-
Bits.ClassDecl.RequiresStoredPropertyInits = 0;
36833682
Bits.ClassDecl.InheritsSuperclassInits = 0;
36843683
Bits.ClassDecl.RawForeignKind = 0;
36853684
Bits.ClassDecl.HasDestructorDecl = 0;
@@ -3835,6 +3834,9 @@ AncestryOptions ClassDecl::checkAncestry() const {
38353834
if (CD->hasResilientMetadata(M, ResilienceExpansion::Maximal))
38363835
result |= AncestryFlags::ResilientOther;
38373836

3837+
if (CD->getAttrs().hasAttribute<RequiresStoredPropertyInitsAttr>())
3838+
result |= AncestryFlags::RequiresStoredPropertyInits;
3839+
38383840
CD = CD->getSuperclassDecl();
38393841
} while (CD != nullptr);
38403842

lib/ClangImporter/ImportDecl.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4436,7 +4436,6 @@ namespace {
44364436
auto a = new (Impl.SwiftContext)
44374437
RequiresStoredPropertyInitsAttr(/*IsImplicit=*/true);
44384438
decl->getAttrs().add(a);
4439-
cast<ClassDecl>(decl)->setRequiresStoredPropertyInits(true);
44404439
}
44414440
}
44424441

lib/Sema/TypeCheckDecl.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3708,14 +3708,6 @@ void TypeChecker::validateDecl(ValueDecl *D) {
37083708

37093709
validateAttributes(*this, D);
37103710

3711-
if (auto CD = dyn_cast<ClassDecl>(nominal)) {
3712-
// Determine whether we require in-class initializers.
3713-
if (CD->getAttrs().hasAttribute<RequiresStoredPropertyInitsAttr>() ||
3714-
(CD->hasSuperclass() &&
3715-
CD->getSuperclassDecl()->requiresStoredPropertyInits()))
3716-
CD->setRequiresStoredPropertyInits(true);
3717-
}
3718-
37193711
if (auto *ED = dyn_cast<EnumDecl>(nominal)) {
37203712
// @objc enums use their raw values as the value representation, so we
37213713
// need to force the values to be checked.

lib/Serialization/Deserialization.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3522,7 +3522,7 @@ class swift::DeclDeserializer {
35223522
StringRef blobData) {
35233523
IdentifierID nameID;
35243524
DeclContextID contextID;
3525-
bool isImplicit, isObjC, requiresStoredPropertyInits;
3525+
bool isImplicit, isObjC;
35263526
bool inheritsSuperclassInitializers;
35273527
GenericEnvironmentID genericEnvID;
35283528
TypeID superclassID;
@@ -3531,7 +3531,6 @@ class swift::DeclDeserializer {
35313531
ArrayRef<uint64_t> rawInheritedAndDependencyIDs;
35323532
decls_block::ClassLayout::readRecord(scratch, nameID, contextID,
35333533
isImplicit, isObjC,
3534-
requiresStoredPropertyInits,
35353534
inheritsSuperclassInitializers,
35363535
genericEnvID, superclassID,
35373536
rawAccessLevel, numConformances,
@@ -3575,8 +3574,6 @@ class swift::DeclDeserializer {
35753574
theClass->setImplicit();
35763575
theClass->setIsObjC(isObjC);
35773576
theClass->setSuperclass(MF.getType(superclassID));
3578-
if (requiresStoredPropertyInits)
3579-
theClass->setRequiresStoredPropertyInits(true);
35803577
if (inheritsSuperclassInitializers)
35813578
theClass->setInheritsSuperclassInitializers();
35823579

lib/Serialization/Serialization.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3301,7 +3301,6 @@ void Serializer::writeDecl(const Decl *D) {
33013301
contextID,
33023302
theClass->isImplicit(),
33033303
theClass->isObjC(),
3304-
theClass->requiresStoredPropertyInits(),
33053304
inheritsSuperclassInitializers,
33063305
addGenericEnvironmentRef(
33073306
theClass->getGenericEnvironment()),
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
import Foundation
3+
4+
@requires_stored_property_inits public class OtherBase : NSObject {}
5+
6+
public class OtherMiddle : OtherBase {}

test/SILGen/ivar_initializer.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %build-clang-importer-objc-overlays
3+
4+
// RUN: %target-swift-emit-silgen(mock-sdk: %clang-importer-sdk-nosource -I %t) -primary-file %s %S/Inputs/ivar_initializer_other.swift | %FileCheck %s
5+
6+
// REQUIRES: objc_interop
7+
8+
import Foundation
9+
10+
@requires_stored_property_inits public class MyBase : NSObject {}
11+
12+
public class MyMiddle : MyBase {}
13+
14+
public class C {}
15+
16+
public class MyDerived : MyMiddle {
17+
var c = C()
18+
}
19+
20+
public class OtherDerived : OtherMiddle {
21+
var c = C()
22+
}
23+
24+
// CHECK-LABEL: sil hidden [ossa] @$s16ivar_initializer9MyDerivedCfeTo : $@convention(objc_method) (@owned MyDerived) -> @owned MyDerived {
25+
26+
// CHECK-LABEL: sil hidden [ossa] @$s16ivar_initializer12OtherDerivedCfeTo : $@convention(objc_method) (@owned OtherDerived) -> @owned OtherDerived {

0 commit comments

Comments
 (0)