Skip to content

Commit eaf12b4

Browse files
committed
Support @objc subclasses of @_objcImpl classes
This rolls in two fixes: • It was previously impossible to call methods on subclasses because of an ambiguity. Cause all member implementations (currently approximated by a hack) to fail access control checks so they will always be excluded. • Having irgen::hasKnownSwiftMetadata() return true for @_objcImplementation classes avoided some metadata generation paths that hadn’t yet been adjusted to work for these classes, but it was never truly correct and it turns out it breaks subclassing (which wants to consume the missing metadata). Remove that workaround.
1 parent e2f69d6 commit eaf12b4

File tree

4 files changed

+68
-7
lines changed

4 files changed

+68
-7
lines changed

lib/AST/Decl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3723,6 +3723,14 @@ static bool checkAccess(const DeclContext *useDC, const ValueDecl *VD,
37233723
bool forConformance,
37243724
bool includeInlineable,
37253725
llvm::function_ref<AccessLevel()> getAccessLevel) {
3726+
// If this is an @_objcImplementation member implementation, forbid access and
3727+
// use the imported decl instead.
3728+
// FIXME: Should just use VD->getObjCInterfaceDecl(), but that doesn't work
3729+
// yet.
3730+
if (auto ED = dyn_cast<ExtensionDecl>(VD->getDeclContext()))
3731+
if (ED->isObjCImplementation() && VD->isObjC())
3732+
return false;
3733+
37263734
if (VD->getASTContext().isAccessControlDisabled())
37273735
return true;
37283736

lib/IRGen/GenClass.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2725,12 +2725,6 @@ bool irgen::hasKnownSwiftMetadata(IRGenModule &IGM, ClassDecl *theClass) {
27252725
return false;
27262726
}
27272727

2728-
// '@_objcImplementation extension' classes have a Swift metadata symbol, even
2729-
// though it only points to ObjC metadata.
2730-
if (!theClass->getObjCImplementationDecls().empty()) {
2731-
return true;
2732-
}
2733-
27342728
// For now, the fact that a declaration was not implemented in Swift
27352729
// is enough to conclusively force us into a slower path.
27362730
// Eventually we might have an attribute here or something based on

test/IRGen/objc_implementation.swift

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// RUN: %FileCheck --input-file %t.ir %s
33
// RUN: %FileCheck --input-file %t.ir --check-prefix NEGATIVE %s
44

5+
// CHECK: [[selector_data_init:@[^, ]+]] = private global [5 x i8] c"init\00", section "__TEXT,__objc_methname,cstring_literals", align 1
6+
// CHECK: [[selector_data_mainMethod_:@[^, ]+]] = private global [12 x i8] c"mainMethod:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
7+
58
//
69
// @_objcImplementation class
710
//
@@ -13,7 +16,6 @@
1316
// TODO: Why the extra i32 field above?
1417

1518
// Class
16-
// CHECK: [[selector_data_mainMethod_:@[^, ]+]] = private global [12 x i8] c"mainMethod:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
1719
// CHECK: [[OBJC_METH_VAR_TYPE_:@[^, ]+]] = private unnamed_addr constant [11 x i8] c"v20@0:8i16\00"
1820
// CHECK: [[_INSTANCE_METHODS_ImplClass:@[^, ]+]] = internal constant { i32, i32, [1 x { i8*, i8*, i8* }] } { i32 24, i32 1, [1 x { i8*, i8*, i8* }] [{ i8*, i8*, i8* } { i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[selector_data_mainMethod_]], i64 0, i64 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* [[OBJC_METH_VAR_TYPE_]], i64 0, i64 0), i8* bitcast (void (%0*, i8*, i32)* @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo" to i8*) }] }, section "__DATA, __objc_data", align 8
1921
// CHECK: [[_DATA_ImplClass:@[^, ]+]] = internal constant { i32, i32, i32, i32, i8*, i8*, { i32, i32, [1 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, i8* } { i32 128, i32 8, i32 8, i32 0, i8* null, i8* getelementptr inbounds ([10 x i8], [10 x i8]* [[OBJC_CLASS_NAME_]], i64 0, i64 0), { i32, i32, [1 x { i8*, i8*, i8* }] }* [[_INSTANCE_METHODS_ImplClass]], i8* null, i8* null, i8* null, i8* null }, section "__DATA, __objc_data", align 8
@@ -46,20 +48,69 @@
4648
}
4749
}
4850

51+
//
52+
// @objc subclass of @_objcImplementation class
53+
//
54+
55+
// Metaclass
56+
// CHECK: @"OBJC_METACLASS_$__TtC19objc_implementation13SwiftSubclass" = global %objc_class { %objc_class* @"OBJC_METACLASS_$_NSObject", %objc_class* @"OBJC_METACLASS_$_ImplClass", %swift.opaque* @_objc_empty_cache, %swift.opaque* null, i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, i8*, i8*, i8*, i8*, i8* }* [[_METACLASS_DATA_SwiftSubclass:@[^, ]+]] to i64) }, align 8
57+
// CHECK: [[OBJC_CLASS_NAME_3:@[^, ]+]] = private unnamed_addr constant [41 x i8] c"_TtC19objc_implementation13SwiftSubclass\00"
58+
// CHECK: [[_METACLASS_DATA_SwiftSubclass]] = internal constant { i32, i32, i32, i32, i8*, i8*, i8*, i8*, i8*, i8*, i8* } { i32 129, i32 40, i32 40, i32 0, i8* null, i8* getelementptr inbounds ([41 x i8], [41 x i8]* [[OBJC_CLASS_NAME_3]], i64 0, i64 0), i8* null, i8* null, i8* null, i8* null, i8* null }, section "__DATA, __objc_const", align 8
59+
60+
// Class
61+
// CHECK: [[OBJC_METH_VAR_TYPE_2:@[^, ]+]] = private unnamed_addr constant [8 x i8] c"@16@0:8\00"
62+
// CHECK: [[_INSTANCE_METHODS_SwiftSubclass:@[^, ]+]] = internal constant { i32, i32, [2 x { i8*, i8*, i8* }] } { i32 24, i32 2, [2 x { i8*, i8*, i8* }] [{ i8*, i8*, i8* } { i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[selector_data_mainMethod_]], i64 0, i64 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* [[OBJC_METH_VAR_TYPE_]], i64 0, i64 0), i8* bitcast (void (%1*, i8*, i32)* @"$s19objc_implementation13SwiftSubclassC10mainMethodyys5Int32VFTo" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[selector_data_init]], i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* [[OBJC_METH_VAR_TYPE_2]], i64 0, i64 0), i8* bitcast (%1* (%1*, i8*)* @"$s19objc_implementation13SwiftSubclassCACycfcTo" to i8*) }] }, section "__DATA, __objc_data", align 8
63+
// CHECK: [[_DATA_SwiftSubclass:@[^, ]+]] = internal constant { i32, i32, i32, i32, i8*, i8*, { i32, i32, [2 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, i8* } { i32 128, i32 8, i32 8, i32 0, i8* null, i8* getelementptr inbounds ([41 x i8], [41 x i8]* [[OBJC_CLASS_NAME_3]], i64 0, i64 0), { i32, i32, [2 x { i8*, i8*, i8* }] }* [[_INSTANCE_METHODS_SwiftSubclass]], i8* null, i8* null, i8* null, i8* null }, section "__DATA, __objc_data", align 8
64+
65+
// Swift metadata
66+
// CHECK: [[module_name:@[^, ]+]] = private constant [20 x i8] c"objc_implementation\00"
67+
// CHECK: @"$s19objc_implementationMXM" = linkonce_odr hidden constant <{ i32, i32, i32 }> <{ i32 0, i32 0, i32 trunc (i64 sub (i64 ptrtoint ([20 x i8]* [[module_name]] to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32, i32 }>, <{ i32, i32, i32 }>* @"$s19objc_implementationMXM", i32 0, i32 2) to i64)) to i32) }>, section "__TEXT,__const", align 4
68+
// CHECK: [[READABLE_SWIFT_CLASS_NAME_SwiftSubclass:@[^, ]+]] = private constant [14 x i8] c"SwiftSubclass\00"
69+
// CHECK: @"symbolic So9ImplClassC" = linkonce_odr hidden constant <{ [13 x i8], i8 }> <{ [13 x i8] c"So9ImplClassC", i8 0 }>, section "__TEXT,__swift5_typeref, regular", align 2
70+
// CHECK: @"$s19objc_implementation13SwiftSubclassCMn" = constant <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }> <{ i32 80, i32 trunc (i64 sub (i64 ptrtoint (<{ i32, i32, i32 }>* @"$s19objc_implementationMXM" to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 1) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint ([14 x i8]* [[READABLE_SWIFT_CLASS_NAME_SwiftSubclass]] to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 2) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (%swift.metadata_response (i64)* @"$s19objc_implementation13SwiftSubclassCMa" to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 3) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint ({ i32, i32, i16, i16, i32 }* @"$s19objc_implementation13SwiftSubclassCMF" to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 4) to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (<{ [13 x i8], i8 }>* @"symbolic So9ImplClassC" to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>, <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s19objc_implementation13SwiftSubclassCMn", i32 0, i32 5) to i64)) to i32), i32 2, i32 10, i32 0, i32 0, i32 10 }>, section "__TEXT,__const", align 4
71+
// CHECK: @"$s19objc_implementation13SwiftSubclassCMf" = internal global <{ void (%T19objc_implementation13SwiftSubclassC*)*, i8**, i64, %objc_class*, %swift.opaque*, %swift.opaque*, i64, i32, i32, i32, i16, i16, i32, i32, <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>*, i8* }> <{ void (%T19objc_implementation13SwiftSubclassC*)* @"$s19objc_implementation13SwiftSubclassCfD", i8** @"$sBOWV", i64 ptrtoint (%objc_class* @"OBJC_METACLASS_$__TtC19objc_implementation13SwiftSubclass" to i64), %objc_class* bitcast (<{ i64, %objc_class*, %swift.opaque*, %swift.opaque*, { i32, i32, i32, i32, i8*, i8*, { i32, i32, [1 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, i8* }* }>* @"OBJC_CLASS_$_ImplClass" to %objc_class*), %swift.opaque* @_objc_empty_cache, %swift.opaque* null, i64 add (i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, { i32, i32, [2 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, i8* }* @_DATA__TtC19objc_implementation13SwiftSubclass to i64), i64 1), i32 0, i32 0, i32 8, i16 7, i16 0, i32 96, i32 16, <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s19objc_implementation13SwiftSubclassCMn", i8* null }>, section "__DATA,__objc_data, regular", align 8
72+
// CHECK: @"symbolic _____ 19objc_implementation13SwiftSubclassC" = linkonce_odr hidden constant <{ i8, i32, i8 }> <{ i8 1, i32 trunc (i64 sub (i64 ptrtoint (<{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>* @"$s19objc_implementation13SwiftSubclassCMn" to i64), i64 ptrtoint (i32* getelementptr inbounds (<{ i8, i32, i8 }>, <{ i8, i32, i8 }>* @"symbolic _____ 19objc_implementation13SwiftSubclassC", i32 0, i32 1) to i64)) to i32), i8 0 }>, section "__TEXT,__swift5_typeref, regular", align 2
73+
// CHECK: @"$s19objc_implementation13SwiftSubclassCMF" = internal constant { i32, i32, i16, i16, i32 } { i32 trunc (i64 sub (i64 ptrtoint (<{ i8, i32, i8 }>* @"symbolic _____ 19objc_implementation13SwiftSubclassC" to i64), i64 ptrtoint ({ i32, i32, i16, i16, i32 }* @"$s19objc_implementation13SwiftSubclassCMF" to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint (<{ [13 x i8], i8 }>* @"symbolic So9ImplClassC" to i64), i64 ptrtoint (i32* getelementptr inbounds ({ i32, i32, i16, i16, i32 }, { i32, i32, i16, i16, i32 }* @"$s19objc_implementation13SwiftSubclassCMF", i32 0, i32 1) to i64)) to i32), i16 7, i16 12, i32 0 }, section "__TEXT,__swift5_fieldmd, regular", align 4
74+
open class SwiftSubclass: ImplClass {
75+
override open func mainMethod(_: Int32) {
76+
print("subclass mainMethod")
77+
}
78+
}
79+
4980
//
5081
// Epilogue
5182
//
5283

5384
// CHECK: @"objc_classes_OBJC_CLASS_$_ImplClass" = internal global i8* bitcast (<{ i64, %objc_class*, %swift.opaque*, %swift.opaque*, { i32, i32, i32, i32, i8*, i8*, { i32, i32, [1 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, i8* }* }>* @"OBJC_CLASS_$_ImplClass" to i8*), section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
85+
// CHECK: @"objc_classes_$s19objc_implementation13SwiftSubclassCN" = internal global i8* bitcast (%swift.type* @"$s19objc_implementation13SwiftSubclassCN" to i8*), section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
5486
// CHECK: @objc_categories = internal global [1 x i8*] [i8* bitcast ({ i8*, %objc_class*, { i32, i32, [1 x { i8*, i8*, i8* }] }*, i8*, i8*, i8*, i8*, i32 }* [[_CATEGORY_ImplClass_Category1]] to i8*)], section "__DATA,__objc_catlist,regular,no_dead_strip", align 8
5587

88+
// CHECK: @"$s19objc_implementation13SwiftSubclassCN" = alias %swift.type, bitcast (i64* getelementptr inbounds (<{ void (%T19objc_implementation13SwiftSubclassC*)*, i8**, i64, %objc_class*, %swift.opaque*, %swift.opaque*, i64, i32, i32, i32, i16, i16, i32, i32, <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>*, i8* }>, <{ void (%T19objc_implementation13SwiftSubclassC*)*, i8**, i64, %objc_class*, %swift.opaque*, %swift.opaque*, i64, i32, i32, i32, i16, i16, i32, i32, <{ i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 }>*, i8* }>* @"$s19objc_implementation13SwiftSubclassCMf", i32 0, i32 2) to %swift.type*)
89+
// CHECK: @"OBJC_CLASS_$__TtC19objc_implementation13SwiftSubclass" = alias %swift.type, %swift.type* @"$s19objc_implementation13SwiftSubclassCN"
5690

5791
//
5892
// Functions
5993
//
6094

95+
public func fn(impl: ImplClass, swiftSub: SwiftSubclass) {
96+
impl.mainMethod(0)
97+
swiftSub.mainMethod(1)
98+
}
99+
61100
// CHECK: define internal void @"$sSo9ImplClassC19objc_implementationE10mainMethodyys5Int32VFTo"
62101
// CHECK: define internal void @"$sSo9ImplClassC19objc_implementationE15category1Methodyys5Int32VFTo"
102+
// CHECK: define internal void @"$s19objc_implementation13SwiftSubclassC10mainMethodyys5Int32VFTo"
103+
// CHECK: define internal %1* @"$s19objc_implementation13SwiftSubclassCACycfcTo"
104+
105+
// CHECK-LABEL: define swiftcc void @"$s19objc_implementation2fn4impl8swiftSubySo9ImplClassC_AA13SwiftSubclassCtF"
106+
// CHECK: [[SEL_1:%[^ ]+]] = load i8*, i8** @"\01L_selector(mainMethod:)", align 8
107+
// CHECK: [[PARAM_impl:%[^ ]+]] = bitcast %TSo9ImplClassC* %0 to %0*
108+
// CHECK: call void bitcast (void ()* @objc_msgSend to void (%0*, i8*, i32)*)(%0* [[PARAM_impl]], i8* [[SEL_1]], i32 0)
109+
// CHECK: [[SEL_2:%[^ ]+]] = load i8*, i8** @"\01L_selector(mainMethod:)", align 8
110+
// CHECK: [[PARAM_swiftSub:%[^ ]+]] = bitcast %T19objc_implementation13SwiftSubclassC* %1 to %1*
111+
// CHECK: call void bitcast (void ()* @objc_msgSend to void (%1*, i8*, i32)*)(%1* [[PARAM_swiftSub]], i8* [[SEL_2]], i32 1)
112+
// CHECK: ret void
113+
// CHECK: }
63114

64115
//
65116
// Not implemented in Swift

test/Interpreter/objc_implementation.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,11 @@ import Foundation
1010

1111
print(ImplClass().someMethod())
1212
// CHECK: ImplClass.someMethod()
13+
14+
class SwiftSubclass: ImplClass {
15+
override func someMethod() -> String { "SwiftSubclass.someMethod()" }
16+
}
17+
18+
print(SwiftSubclass().someMethod())
19+
// CHECK: SwiftSubclass.someMethod()
20+

0 commit comments

Comments
 (0)