Skip to content

Commit 31d8cad

Browse files
committed
Make objcImpl classes derive inherited inits
A class that uses @objcImplementation but does not explicitly declare any designated initializers previously did not override the superclass initializers, so its stored properties would not be initialized. Opt these classes into that logic and adjust it to add the initializers to the @objcImplementation extension instead of the ClassDecl itself. Fixes rdar://105008242.
1 parent f64e7d3 commit 31d8cad

File tree

5 files changed

+70
-16
lines changed

5 files changed

+70
-16
lines changed

lib/SILGen/SILGenConstructor.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1057,7 +1057,8 @@ emitMemberInit(SILGenFunction &SGF, VarDecl *selfDecl, Pattern *pattern) {
10571057
slot = SGF.B.createStructElementAddr(pattern, self.forward(SGF), field,
10581058
fieldTy.getAddressType());
10591059
} else {
1060-
assert(isa<ClassDecl>(field->getDeclContext()));
1060+
assert(isa<ClassDecl>(field->getDeclContext()->
1061+
getImplementedObjCContext()));
10611062
slot = SGF.B.createRefElementAddr(pattern, self.forward(SGF), field,
10621063
fieldTy.getAddressType());
10631064
}
@@ -1154,7 +1155,7 @@ void SILGenFunction::emitMemberInitializers(DeclContext *dc,
11541155
NominalTypeDecl *nominal) {
11551156
auto subs = getSubstitutionsForPropertyInitializer(dc, nominal);
11561157

1157-
for (auto member : nominal->getMembers()) {
1158+
for (auto member : nominal->getImplementationContext()->getMembers()) {
11581159
// Find instance pattern binding declarations that have initializers.
11591160
if (auto pbd = dyn_cast<PatternBindingDecl>(member)) {
11601161
if (pbd->isStatic()) continue;

lib/Sema/CodeSynthesis.cpp

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -619,12 +619,26 @@ createDesignatedInitOverrideGenericParams(ASTContext &ctx,
619619
ArrayRef<RequirementRepr>(), SourceLoc());
620620
}
621621

622+
/// True if the type has an opaque clang implementation, meaning it is imported
623+
/// and doesn't have an \c \@objcImplementation extension.
624+
static bool hasClangImplementation(const NominalTypeDecl *decl) {
625+
return decl->hasClangNode() && !decl->getObjCImplementationDecl();
626+
}
627+
628+
/// True if \p member is in the main body of \p ty, where the "main body" is
629+
/// either the type itself (the usual case) or its \c \@objcImplementation
630+
/// extension (if one is present).
631+
static bool isInMainBody(ValueDecl *member, NominalTypeDecl *ty) {
632+
return member->getDeclContext() ==
633+
ty->getImplementationContext()->getAsGenericContext();
634+
}
635+
622636
static void
623637
configureInheritedDesignatedInitAttributes(ClassDecl *classDecl,
624638
ConstructorDecl *ctor,
625639
ConstructorDecl *superclassCtor,
626640
ASTContext &ctx) {
627-
assert(ctor->getDeclContext() == classDecl);
641+
assert(isInMainBody(ctor, classDecl));
628642

629643
AccessLevel access = classDecl->getFormalAccess();
630644
access = std::max(access, AccessLevel::Internal);
@@ -856,6 +870,7 @@ createDesignatedInitOverride(ClassDecl *classDecl,
856870

857871
// Create the initializer declaration, inheriting the name,
858872
// failability, and throws from the superclass initializer.
873+
auto implCtx = classDecl->getImplementationContext()->getAsGenericContext();
859874
auto ctor =
860875
new (ctx) ConstructorDecl(superclassCtor->getName(),
861876
classDecl->getBraces().Start,
@@ -865,8 +880,7 @@ createDesignatedInitOverride(ClassDecl *classDecl,
865880
/*AsyncLoc=*/SourceLoc(),
866881
/*Throws=*/superclassCtor->hasThrows(),
867882
/*ThrowsLoc=*/SourceLoc(),
868-
bodyParams, genericParams,
869-
classDecl);
883+
bodyParams, genericParams, implCtx);
870884

871885
ctor->setImplicit();
872886

@@ -988,9 +1002,9 @@ static void diagnoseMissingRequiredInitializer(
9881002

9891003
bool AreAllStoredPropertiesDefaultInitableRequest::evaluate(
9901004
Evaluator &evaluator, NominalTypeDecl *decl) const {
991-
assert(!decl->hasClangNode());
1005+
assert(!hasClangImplementation(decl));
9921006

993-
for (auto member : decl->getMembers()) {
1007+
for (auto member : decl->getImplementationContext()->getMembers()) {
9941008
// If a stored property lacks an initial value and if there is no way to
9951009
// synthesize an initial value (e.g. for an optional) then we suppress
9961010
// generation of the default initializer.
@@ -1031,7 +1045,7 @@ bool AreAllStoredPropertiesDefaultInitableRequest::evaluate(
10311045

10321046
static bool areAllStoredPropertiesDefaultInitializable(Evaluator &eval,
10331047
NominalTypeDecl *decl) {
1034-
if (decl->hasClangNode())
1048+
if (hasClangImplementation(decl))
10351049
return true;
10361050

10371051
return evaluateOrDefault(
@@ -1041,11 +1055,11 @@ static bool areAllStoredPropertiesDefaultInitializable(Evaluator &eval,
10411055
bool
10421056
HasUserDefinedDesignatedInitRequest::evaluate(Evaluator &evaluator,
10431057
NominalTypeDecl *decl) const {
1044-
assert(!decl->hasClangNode());
1058+
assert(!hasClangImplementation(decl));
10451059

10461060
auto results = decl->lookupDirect(DeclBaseName::createConstructor());
10471061
for (auto *member : results) {
1048-
if (isa<ExtensionDecl>(member->getDeclContext()))
1062+
if (!isInMainBody(member, decl))
10491063
continue;
10501064

10511065
auto *ctor = cast<ConstructorDecl>(member);
@@ -1059,7 +1073,7 @@ HasUserDefinedDesignatedInitRequest::evaluate(Evaluator &evaluator,
10591073
static bool hasUserDefinedDesignatedInit(Evaluator &eval,
10601074
NominalTypeDecl *decl) {
10611075
// Imported decls don't have a designated initializer defined by the user.
1062-
if (decl->hasClangNode())
1076+
if (hasClangImplementation(decl))
10631077
return false;
10641078

10651079
return evaluateOrDefault(eval, HasUserDefinedDesignatedInitRequest{decl},
@@ -1086,7 +1100,7 @@ static void collectNonOveriddenSuperclassInits(
10861100

10871101
auto ctors = subclass->lookupDirect(DeclBaseName::createConstructor());
10881102
for (auto *member : ctors) {
1089-
if (isa<ExtensionDecl>(member->getDeclContext()))
1103+
if (!isInMainBody(member, subclass))
10901104
continue;
10911105

10921106
auto *ctor = cast<ConstructorDecl>(member);
@@ -1189,7 +1203,7 @@ static void addImplicitInheritedConstructorsToClass(ClassDecl *decl) {
11891203

11901204
auto results = decl->lookupDirect(DeclBaseName::createConstructor());
11911205
for (auto *member : results) {
1192-
if (isa<ExtensionDecl>(member->getDeclContext()))
1206+
if (!isInMainBody(member, decl))
11931207
continue;
11941208

11951209
auto *ctor = cast<ConstructorDecl>(member);
@@ -1217,7 +1231,7 @@ static void addImplicitInheritedConstructorsToClass(ClassDecl *decl) {
12171231

12181232
if (auto ctor = createDesignatedInitOverride(
12191233
decl, superclassCtor, kind, ctx)) {
1220-
decl->addMember(ctor);
1234+
decl->getImplementationContext()->addMember(ctor);
12211235
}
12221236
}
12231237
}
@@ -1258,7 +1272,7 @@ InheritsSuperclassInitializersRequest::evaluate(Evaluator &eval,
12581272

12591273
static bool shouldAttemptInitializerSynthesis(const NominalTypeDecl *decl) {
12601274
// Don't synthesize initializers for imported decls.
1261-
if (decl->hasClangNode())
1275+
if (hasClangImplementation(decl))
12621276
return false;
12631277

12641278
// Don't add implicit constructors in module interfaces.

lib/Sema/TypeCheckDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2737,7 +2737,7 @@ static ArrayRef<Decl *> evaluateMembersRequest(
27372737
return ctx.AllocateCopy(result);
27382738
}
27392739

2740-
auto nominal = dyn_cast<NominalTypeDecl>(idc);
2740+
auto nominal = dyn_cast<NominalTypeDecl>(dc->getImplementedObjCContext());
27412741

27422742
if (nominal) {
27432743
// We need to add implicit initializers because they

test/IRGen/Inputs/objc_implementation.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,12 @@
3030
- (void)noImplMethod:(int)param;
3131

3232
@end
33+
34+
@interface NoInitImplClass: NSObject
35+
36+
@property (readonly, strong, nonnull) NSString *s1;
37+
@property (strong, nonnull) NSString *s2;
38+
@property (readonly, strong, nonnull) NSString *s3;
39+
@property (strong, nonnull) NSString *s4;
40+
41+
@end

test/IRGen/objc_implementation.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,24 @@
6666
}
6767
}
6868

69+
//
70+
// Second @_objcImplementation class, inherited initializer
71+
//
72+
73+
// CHECK: @"OBJC_METACLASS_$_NoInitImplClass" = global %objc_class { %objc_class* @"OBJC_METACLASS_$_NSObject", %objc_class* @"OBJC_METACLASS_$_NSObject", %swift.opaque* @_objc_empty_cache, %swift.opaque* null, i64 ptrtoint ({ i32, i32, i32, i32, i8*, i8*, i8*, i8*, i8*, i8*, i8* }* @_METACLASS_DATA_NoInitImplClass to i64) }, align 8
74+
// CHECK: @_METACLASS_DATA_NoInitImplClass = 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 ([16 x i8], [16 x i8]* @.str.15.NoInitImplClass, i64 0, i64 0), i8* null, i8* null, i8* null, i8* null, i8* null }, section "__DATA, __objc_const", align 8
75+
// CHECK: @_INSTANCE_METHODS_NoInitImplClass = internal constant { i32, i32, [8 x { i8*, i8*, i8* }] } { i32 24, i32 8, [8 x { i8*, i8*, i8* }] [{ i8*, i8*, i8* } { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_selector_data(s1)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.@16@0:8", i64 0, i64 0), i8* bitcast (%2* (%3*, i8*)* @"$sSo15NoInitImplClassC19objc_implementationE2s1SSvgTo" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_selector_data(s2)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.@16@0:8", i64 0, i64 0), i8* bitcast (%2* (%3*, i8*)* @"$sSo15NoInitImplClassC19objc_implementationE2s2SSvgTo" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01L_selector_data(setS2:)", i64 0, i64 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @".str.10.v24@0:8@16", i64 0, i64 0), i8* bitcast (void (%3*, i8*, %2*)* @"$sSo15NoInitImplClassC19objc_implementationE2s2SSvsTo" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_selector_data(s3)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.@16@0:8", i64 0, i64 0), i8* bitcast (%2* (%3*, i8*)* @"$sSo15NoInitImplClassC19objc_implementationE2s3SSvgTo" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"\01L_selector_data(s4)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.@16@0:8", i64 0, i64 0), i8* bitcast (%2* (%3*, i8*)* @"$sSo15NoInitImplClassC19objc_implementationE2s4SSvgTo" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"\01L_selector_data(setS4:)", i64 0, i64 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @".str.10.v24@0:8@16", i64 0, i64 0), i8* bitcast (void (%3*, i8*, %2*)* @"$sSo15NoInitImplClassC19objc_implementationE2s4SSvsTo" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([5 x i8], [5 x i8]* @"\01L_selector_data(init)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.@16@0:8", i64 0, i64 0), i8* bitcast (%3* (%3*, i8*)* @"$sSo15NoInitImplClassC19objc_implementationEABycfcTo" to i8*) }, { i8*, i8*, i8* } { i8* getelementptr inbounds ([14 x i8], [14 x i8]* @"\01L_selector_data(.cxx_destruct)", i64 0, i64 0), i8* getelementptr inbounds ([8 x i8], [8 x i8]* @".str.7.v16@0:8", i64 0, i64 0), i8* bitcast (void (%3*, i8*)* @"$sSo15NoInitImplClassCfETo" to i8*) }] }, section "__DATA, __objc_data", align 8
76+
// CHECK: @_IVARS_NoInitImplClass = internal constant { i32, i32, [4 x { i64*, i8*, i8*, i32, i32 }] } { i32 32, i32 4, [4 x { i64*, i8*, i8*, i32, i32 }] [{ i64*, i8*, i8*, i32, i32 } { i64* @"$sSo15NoInitImplClassC19objc_implementationE2s1SSvpWvd", i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2.s1, i64 0, i64 0), i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.0., i64 0, i64 0), i32 3, i32 16 }, { i64*, i8*, i8*, i32, i32 } { i64* @"$sSo15NoInitImplClassC19objc_implementationE2s2SSvpWvd", i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2.s2, i64 0, i64 0), i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.0., i64 0, i64 0), i32 3, i32 16 }, { i64*, i8*, i8*, i32, i32 } { i64* @"$sSo15NoInitImplClassC19objc_implementationE2s3SSvpWvd", i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2.s3, i64 0, i64 0), i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.0., i64 0, i64 0), i32 3, i32 16 }, { i64*, i8*, i8*, i32, i32 } { i64* @"$sSo15NoInitImplClassC19objc_implementationE2s4SSvpWvd", i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2.s4, i64 0, i64 0), i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.0., i64 0, i64 0), i32 3, i32 16 }] }, section "__DATA, __objc_const", align 8
77+
// CHECK: @_PROPERTIES_NoInitImplClass = internal constant { i32, i32, [4 x { i8*, i8* }] } { i32 16, i32 4, [4 x { i8*, i8* }] [{ i8*, i8* } { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2.s1, i64 0, i64 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @".str.16.T@\22NSString\22,N,R", i64 0, i64 0) }, { i8*, i8* } { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2.s2, i64 0, i64 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @".str.16.T@\22NSString\22,N,C", i64 0, i64 0) }, { i8*, i8* } { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2.s3, i64 0, i64 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @".str.16.T@\22NSString\22,N,R", i64 0, i64 0) }, { i8*, i8* } { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2.s4, i64 0, i64 0), i8* getelementptr inbounds ([17 x i8], [17 x i8]* @".str.16.T@\22NSString\22,N,C", i64 0, i64 0) }] }, section "__DATA, __objc_const", align 8
78+
// CHECK: @_DATA_NoInitImplClass = internal constant { i32, i32, i32, i32, i8*, i8*, { i32, i32, [8 x { i8*, i8*, i8* }] }*, i8*, { i32, i32, [4 x { i64*, i8*, i8*, i32, i32 }] }*, i8*, { i32, i32, [4 x { i8*, i8* }] }* } { i32 388, i32 8, i32 72, i32 0, i8* null, i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.15.NoInitImplClass, i64 0, i64 0), { i32, i32, [8 x { i8*, i8*, i8* }] }* @_INSTANCE_METHODS_NoInitImplClass, i8* null, { i32, i32, [4 x { i64*, i8*, i8*, i32, i32 }] }* @_IVARS_NoInitImplClass, i8* null, { i32, i32, [4 x { i8*, i8* }] }* @_PROPERTIES_NoInitImplClass }, section "__DATA, __objc_data", align 8
79+
// CHECK: @"OBJC_CLASS_$_NoInitImplClass" = global <{ i64, %objc_class*, %swift.opaque*, %swift.opaque*, { i32, i32, i32, i32, i8*, i8*, { i32, i32, [8 x { i8*, i8*, i8* }] }*, i8*, { i32, i32, [4 x { i64*, i8*, i8*, i32, i32 }] }*, i8*, { i32, i32, [4 x { i8*, i8* }] }* }* }> <{ i64 ptrtoint (%objc_class* @"OBJC_METACLASS_$_NoInitImplClass" to i64), %objc_class* @"OBJC_CLASS_$_NSObject", %swift.opaque* @_objc_empty_cache, %swift.opaque* null, { i32, i32, i32, i32, i8*, i8*, { i32, i32, [8 x { i8*, i8*, i8* }] }*, i8*, { i32, i32, [4 x { i64*, i8*, i8*, i32, i32 }] }*, i8*, { i32, i32, [4 x { i8*, i8* }] }* }* @_DATA_NoInitImplClass }>, section "__DATA,__objc_data, regular", align 8
80+
@_objcImplementation extension NoInitImplClass {
81+
@objc let s1 = "s1v"
82+
@objc var s2 = "s2v"
83+
@objc(s3) let s3 = "s3v"
84+
@objc(s4) var s4 = "s4v"
85+
}
86+
6987
//
7088
// @objc subclass of @_objcImplementation class
7189
//
@@ -172,6 +190,18 @@ public func fn(impl: ImplClass, swiftSub: SwiftSubclass) {
172190
// ObjC calling convention -[ImplClass(Category1) category1Method:]
173191
// CHECK-LABEL: define internal void @"$sSo9ImplClassC19objc_implementationE15category1Methodyys5Int32VFTo"
174192

193+
// Swift calling convention -[NoInitImplClass init]
194+
// CHECK-LABEL: define swiftcc %TSo15NoInitImplClassC* @"$sSo15NoInitImplClassC19objc_implementationEABycfc"
195+
// CHECK-DAG: load i64, i64* @"$sSo15NoInitImplClassC19objc_implementationE2s1SSvpWvd", align 8
196+
// CHECK-DAG: load i64, i64* @"$sSo15NoInitImplClassC19objc_implementationE2s2SSvpWvd", align 8
197+
// CHECK-DAG: load i64, i64* @"$sSo15NoInitImplClassC19objc_implementationE2s3SSvpWvd", align 8
198+
// CHECK-DAG: load i64, i64* @"$sSo15NoInitImplClassC19objc_implementationE2s4SSvpWvd", align 8
199+
// CHECK: [[SEL_init:%[^ ]+]] = load i8*, i8** @"\01L_selector(init)", align 8
200+
// CHECK: call %0* bitcast (void ()* @objc_msgSendSuper{{.*}} [[SEL_init]])
201+
202+
// ObjC calling convention -[NoInitImplClass init]
203+
// CHECK-LABEL: define internal %3* @"$sSo15NoInitImplClassC19objc_implementationEABycfcTo"
204+
175205
// Swift calling convention SwiftSubclass.mainMethod(_:)
176206
// CHECK-LABEL: define swiftcc void @"$s19objc_implementation13SwiftSubclassC10mainMethodyys5Int32VF"
177207

0 commit comments

Comments
 (0)