Skip to content

Commit 4f0f11f

Browse files
authored
Merge pull request #21260 from slavapestov/objc-members-transitivity
AST: Rework @objcMembers inheritance to not depend on validation order
2 parents 25e4c60 + bfcf24e commit 4f0f11f

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
@@ -529,7 +529,7 @@ class alignas(1 << DeclAlignInBits) Decl {
529529
NumRequirementsInSignature : 16
530530
);
531531

532-
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+2+1+2+1+3+1+1,
532+
SWIFT_INLINE_BITFIELD(ClassDecl, NominalTypeDecl, 1+2+1+2+1+3+1+1+1+1,
533533
/// Whether this class requires all of its instance variables to
534534
/// have in-class initializers.
535535
RequiresStoredPropertyInits : 1,
@@ -553,6 +553,10 @@ class alignas(1 << DeclAlignInBits) Decl {
553553
/// Whether the class has @objc ancestry.
554554
ObjCKind : 3,
555555

556+
/// Whether this class has @objc members.
557+
HasObjCMembersComputed : 1,
558+
HasObjCMembers : 1,
559+
556560
HasMissingDesignatedInitializers : 1,
557561
HasMissingVTableEntries : 1
558562
);
@@ -3562,6 +3566,8 @@ class ClassDecl final : public NominalTypeDecl {
35623566
friend class SuperclassTypeRequest;
35633567
friend class TypeChecker;
35643568

3569+
bool hasObjCMembersSlow();
3570+
35653571
public:
35663572
ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
35673573
MutableArrayRef<TypeLoc> Inherited,
@@ -3720,11 +3726,20 @@ class ClassDecl final : public NominalTypeDecl {
37203726
Bits.ClassDecl.InheritsSuperclassInits = true;
37213727
}
37223728

3723-
/// Figure out if this class has any @objc ancestors, in which case it should
3724-
/// have implicitly @objc members. Note that a class with generic ancestry
3725-
/// might have implicitly @objc members, but will never itself be @objc.
3729+
/// Returns if this class has any @objc ancestors, or if it is directly
3730+
/// visible to Objective-C. The latter is a stronger condition which is only
3731+
/// true if the class does not have any generic ancestry.
37263732
ObjCClassKind checkObjCAncestry() const;
37273733

3734+
/// Returns if the class has implicitly @objc members. This is true if any
3735+
/// ancestor class has the @objcMembers attribute.
3736+
bool hasObjCMembers() const {
3737+
if (Bits.ClassDecl.HasObjCMembersComputed)
3738+
return Bits.ClassDecl.HasObjCMembers;
3739+
3740+
return const_cast<ClassDecl *>(this)->hasObjCMembersSlow();
3741+
}
3742+
37283743
/// The type of metaclass to use for a class.
37293744
enum class MetaclassKind : uint8_t {
37303745
ObjC,

lib/AST/Decl.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3445,6 +3445,8 @@ ClassDecl::ClassDecl(SourceLoc ClassLoc, Identifier Name, SourceLoc NameLoc,
34453445
Bits.ClassDecl.RawForeignKind = 0;
34463446
Bits.ClassDecl.HasDestructorDecl = 0;
34473447
Bits.ClassDecl.ObjCKind = 0;
3448+
Bits.ClassDecl.HasObjCMembersComputed = 0;
3449+
Bits.ClassDecl.HasObjCMembers = 0;
34483450
Bits.ClassDecl.HasMissingDesignatedInitializers = 0;
34493451
Bits.ClassDecl.HasMissingVTableEntries = 0;
34503452
}
@@ -3607,6 +3609,20 @@ ObjCClassKind ClassDecl::checkObjCAncestry() const {
36073609
return kind;
36083610
}
36093611

3612+
bool ClassDecl::hasObjCMembersSlow() {
3613+
// Don't attempt to calculate this again.
3614+
Bits.ClassDecl.HasObjCMembersComputed = true;
3615+
3616+
bool result = false;
3617+
if (getAttrs().hasAttribute<ObjCMembersAttr>())
3618+
result = true;
3619+
else if (auto *superclassDecl = getSuperclassDecl())
3620+
result = superclassDecl->hasObjCMembers();
3621+
3622+
Bits.ClassDecl.HasObjCMembers = result;
3623+
return result;
3624+
}
3625+
36103626
ClassDecl::MetaclassKind ClassDecl::getMetaclassKind() const {
36113627
assert(getASTContext().LangOpts.EnableObjCInterop &&
36123628
"querying metaclass kind without objc interop");

lib/ClangImporter/ImportDecl.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7419,13 +7419,9 @@ void ClangImporter::Implementation::importAttributes(
74197419
return;
74207420
}
74217421

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

lib/Sema/TypeCheckDecl.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3612,14 +3612,6 @@ void TypeChecker::validateDecl(ValueDecl *D) {
36123612
(CD->hasSuperclass() &&
36133613
CD->getSuperclassDecl()->requiresStoredPropertyInits()))
36143614
CD->setRequiresStoredPropertyInits(true);
3615-
3616-
// Inherit @objcMembers.
3617-
if (auto superclass = CD->getSuperclassDecl()) {
3618-
if (superclass->getAttrs().hasAttribute<ObjCMembersAttr>() &&
3619-
!CD->getAttrs().hasAttribute<ObjCMembersAttr>()) {
3620-
CD->getAttrs().add(new (Context) ObjCMembersAttr(/*IsImplicit=*/true));
3621-
}
3622-
}
36233615
}
36243616

36253617
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)