Skip to content

Commit b9dc915

Browse files
authored
Merge pull request #21261 from slavapestov/objc-members-transitivity-5.0
AST: Rework @objcMembers inheritance to not depend on validation order [5.0]
2 parents d8bc889 + 5787b95 commit b9dc915

File tree

7 files changed

+48
-21
lines changed

7 files changed

+48
-21
lines changed

include/swift/AST/Decl.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ class alignas(1 << DeclAlignInBits) Decl {
524524
NumRequirementsInSignature : 16
525525
);
526526

527-
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+2+1+2+1+3+1+1,
527+
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+2+1+2+1+3+1+1+1+1,
528528
/// Whether this class requires all of its instance variables to
529529
/// have in-class initializers.
530530
RequiresStoredPropertyInits : 1,
@@ -548,6 +548,10 @@ class alignas(1 << DeclAlignInBits) Decl {
548548
/// Whether the class has @objc ancestry.
549549
ObjCKind : 3,
550550

551+
/// Whether this class has @objc members.
552+
HasObjCMembersComputed : 1,
553+
HasObjCMembers : 1,
554+
551555
HasMissingDesignatedInitializers : 1,
552556
HasMissingVTableEntries : 1
553557
);
@@ -3573,6 +3577,8 @@ class ClassDecl final : public NominalTypeDecl {
35733577
friend class SuperclassTypeRequest;
35743578
friend class TypeChecker;
35753579

3580+
bool hasObjCMembersSlow();
3581+
35763582
public:
35773583
ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
35783584
MutableArrayRef<TypeLoc> Inherited,
@@ -3731,11 +3737,20 @@ class ClassDecl final : public NominalTypeDecl {
37313737
Bits.ClassDecl.InheritsSuperclassInits = true;
37323738
}
37333739

3734-
/// Figure out if this class has any @objc ancestors, in which case it should
3735-
/// have implicitly @objc members. Note that a class with generic ancestry
3736-
/// might have implicitly @objc members, but will never itself be @objc.
3740+
/// Returns if this class has any @objc ancestors, or if it is directly
3741+
/// visible to Objective-C. The latter is a stronger condition which is only
3742+
/// true if the class does not have any generic ancestry.
37373743
ObjCClassKind checkObjCAncestry() const;
37383744

3745+
/// Returns if the class has implicitly @objc members. This is true if any
3746+
/// ancestor class has the @objcMembers attribute.
3747+
bool hasObjCMembers() const {
3748+
if (Bits.ClassDecl.HasObjCMembersComputed)
3749+
return Bits.ClassDecl.HasObjCMembers;
3750+
3751+
return const_cast<ClassDecl *>(this)->hasObjCMembersSlow();
3752+
}
3753+
37393754
/// The type of metaclass to use for a class.
37403755
enum class MetaclassKind : uint8_t {
37413756
ObjC,

lib/AST/Decl.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3437,6 +3437,8 @@ ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
34373437
Bits.ClassDecl.RawForeignKind = 0;
34383438
Bits.ClassDecl.HasDestructorDecl = 0;
34393439
Bits.ClassDecl.ObjCKind = 0;
3440+
Bits.ClassDecl.HasObjCMembersComputed = 0;
3441+
Bits.ClassDecl.HasObjCMembers = 0;
34403442
Bits.ClassDecl.HasMissingDesignatedInitializers = 0;
34413443
Bits.ClassDecl.HasMissingVTableEntries = 0;
34423444
}
@@ -3599,6 +3601,20 @@ ObjCClassKind ClassDecl::checkObjCAncestry() const {
35993601
return kind;
36003602
}
36013603

3604+
bool ClassDecl::hasObjCMembersSlow() {
3605+
// Don't attempt to calculate this again.
3606+
Bits.ClassDecl.HasObjCMembersComputed = true;
3607+
3608+
bool result = false;
3609+
if (getAttrs().hasAttribute<ObjCMembersAttr>())
3610+
result = true;
3611+
else if (auto *superclassDecl = getSuperclassDecl())
3612+
result = superclassDecl->hasObjCMembers();
3613+
3614+
Bits.ClassDecl.HasObjCMembers = result;
3615+
return result;
3616+
}
3617+
36023618
ClassDecl::MetaclassKind ClassDecl::getMetaclassKind() const {
36033619
assert(getASTContext().LangOpts.EnableObjCInterop &&
36043620
"querying metaclass kind without objc interop");

lib/ClangImporter/ImportDecl.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7416,13 +7416,9 @@ void ClangImporter::Implementation::importAttributes(
74167416
return;
74177417
}
74187418

7419-
// Map Clang's swift_objc_members attribute to @objcMembers. Also handle
7420-
// inheritance of @objcMembers by looking at the superclass.
7421-
if (ID->hasAttr<clang::SwiftObjCMembersAttr>() ||
7422-
(isa<ClassDecl>(MappedDecl) &&
7423-
cast<ClassDecl>(MappedDecl)->hasSuperclass() &&
7424-
cast<ClassDecl>(MappedDecl)->getSuperclassDecl()
7425-
->getAttrs().hasAttribute<ObjCMembersAttr>())) {
7419+
// Map Clang's swift_objc_members attribute to @objcMembers.
7420+
if (ID->hasAttr<clang::SwiftObjCMembersAttr>() &&
7421+
isa<ClassDecl>(MappedDecl)) {
74267422
if (!MappedDecl->getAttrs().hasAttribute<ObjCMembersAttr>()) {
74277423
auto attr = new (C) ObjCMembersAttr(/*IsImplicit=*/true);
74287424
MappedDecl->getAttrs().add(attr);

lib/Sema/TypeCheckDecl.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3969,14 +3969,6 @@ void TypeChecker::validateDecl(ValueDecl *D) {
39693969
(CD->hasSuperclass() &&
39703970
CD->getSuperclassDecl()->requiresStoredPropertyInits()))
39713971
CD->setRequiresStoredPropertyInits(true);
3972-
3973-
// Inherit @objcMembers.
3974-
if (auto superclass = CD->getSuperclassDecl()) {
3975-
if (superclass->getAttrs().hasAttribute<ObjCMembersAttr>() &&
3976-
!CD->getAttrs().hasAttribute<ObjCMembersAttr>()) {
3977-
CD->getAttrs().add(new (Context) ObjCMembersAttr(/*IsImplicit=*/true));
3978-
}
3979-
}
39803972
}
39813973

39823974
if (auto *ED = dyn_cast<EnumDecl>(nominal)) {

lib/Sema/TypeCheckDeclObjC.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ static bool isMemberOfObjCMembersClass(const ValueDecl *VD) {
988988
auto classDecl = VD->getDeclContext()->getSelfClassDecl();
989989
if (!classDecl) return false;
990990

991-
return classDecl->getAttrs().hasAttribute<ObjCMembersAttr>();
991+
return classDecl->hasObjCMembers();
992992
}
993993

994994
// A class is @objc if it does not have generic ancestry, and it either has
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@objcMembers class BaseClassWithObjCMembers {}
2+
3+
class OtherClassWithObjCMembers : BaseClassWithObjCMembers {}

test/attr/attr_objcMembers.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify %s
1+
// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -typecheck -verify %s %S/Inputs/attr_objcMembers_other.swift
22
// REQUIRES: objc_interop
33

44
import Foundation
@@ -24,12 +24,17 @@ extension SubClassOfSomeClassWithObjCMembers {
2424
func wibble() { }
2525
}
2626

27+
class SubClassOfOtherClassWithObjCMembers : OtherClassWithObjCMembers {
28+
func quux() { }
29+
}
30+
2731
// @objc should be inferred for everything referenced here.
2832
func selectorTest() {
2933
_ = #selector(SomeClassWithObjCMembers.foo)
3034
_ = #selector(getter: SomeClassWithObjCMembers.bar)
3135
_ = #selector(SubClassOfSomeClassWithObjCMembers.baz)
3236
_ = #selector(SubClassOfSomeClassWithObjCMembers.wibble)
37+
_ = #selector(SubClassOfOtherClassWithObjCMembers.quux)
3338
}
3439

3540
@nonobjc extension SomeClassWithObjCMembers {

0 commit comments

Comments
 (0)