Skip to content

Commit aa85e45

Browse files
authored
Don't force inlinable constructors to delegate in non-resilient code (#14721)
This restriction came from wanting to make resilient and non-resilient code follow the same rules whenever possible, but after thinking about it a bit more we realized there was no reason why you /wouldn't/ just mark your structs @_fixed_layout in non-resilient libraries anyway. Since that (currently?) doesn't affect what you can do with the struct across module boundaries, and since the layout of the struct is available anyway in a non-resilient library, there's no real downside, which means it's a meaningless restriction. The same logic doesn't /quite/ apply to classes, since classes are normally much more flexible than structs. (For example, you could add a stored property to a class without recompiling clients, as long as no initializers are inlined.) But it's close enough that we don't want to put in the restriction at this time. All of this is about attributes that haven't been finalized yet anyway (hence the leading underscore), but it's still useful information. rdar://problem/37408668
1 parent fbe65e2 commit aa85e45

File tree

4 files changed

+54
-41
lines changed

4 files changed

+54
-41
lines changed

lib/AST/Decl.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5471,7 +5471,11 @@ ConstructorDecl::getDelegatingOrChainedInitKind(DiagnosticEngine *diags,
54715471
// always delegating. This occurs if the struct type is not fixed layout,
54725472
// and the constructor is either inlinable or defined in another module.
54735473
if (Kind == BodyInitKind::None && isa<StructDecl>(NTD)) {
5474-
if (NTD->isFormallyResilient() &&
5474+
// Note: This is specifically not using isFormallyResilient. We relax this
5475+
// rule for structs in non-resilient modules so that they can have inlinable
5476+
// constructors, as long as those constructors don't reference private
5477+
// declarations.
5478+
if (NTD->isResilient() &&
54755479
getResilienceExpansion() == ResilienceExpansion::Minimal) {
54765480
Kind = BodyInitKind::Delegating;
54775481

lib/Sema/TypeCheckStmt.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,9 +1620,12 @@ bool TypeChecker::typeCheckConstructorBodyUntil(ConstructorDecl *ctor,
16201620
}
16211621

16221622
// An inlinable constructor in a class must always be delegating,
1623-
// unless the class is formally '@_fixed_layout'.
1624-
if (!isDelegating &&
1625-
ClassD->isFormallyResilient() &&
1623+
// unless the class is '@_fixed_layout'.
1624+
// Note: This is specifically not using isFormallyResilient. We relax this
1625+
// rule for classes in non-resilient modules so that they can have inlinable
1626+
// constructors, as long as those constructors don't reference private
1627+
// declarations.
1628+
if (!isDelegating && ClassD->isResilient() &&
16261629
ctor->getResilienceExpansion() == ResilienceExpansion::Minimal) {
16271630
diagnose(ctor, diag::class_designated_init_inlineable_resilient,
16281631
ClassD->getDeclaredInterfaceType(),
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// RUN: %empty-directory(%t)
2+
3+
// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../../Inputs/resilient_struct.swift
4+
// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../../Inputs/resilient_protocol.swift
5+
6+
// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -I %t %s
7+
// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -enable-resilience -I %t %s
8+
9+
// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -I %t %s
10+
// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -enable-resilience -I %t %s
11+
12+
import resilient_struct
13+
import resilient_protocol
14+
15+
// Size is not @_fixed_layout, so we cannot define a new designated initializer
16+
extension Size {
17+
init(ww: Int, hh: Int) {
18+
self.w = ww
19+
self.h = hh // expected-error {{'let' property 'h' may not be initialized directly; use "self.init(...)" or "self = ..." instead}}
20+
}
21+
22+
// This is OK
23+
init(www: Int, hhh: Int) {
24+
self.init(w: www, h: hhh)
25+
}
26+
27+
// This is OK
28+
init(other: Size) {
29+
self = other
30+
}
31+
}
32+
33+
// Protocol extension initializers are OK too
34+
extension OtherResilientProtocol {
35+
public init(other: Self) {
36+
self = other
37+
}
38+
}

test/decl/init/resilience.swift

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,9 @@
1-
// RUN: %empty-directory(%t)
1+
// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -enable-resilience %s -DRESILIENT
2+
// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -enable-resilience %s -DRESILIENT
23

3-
// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../../Inputs/resilient_struct.swift
4-
// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../../Inputs/resilient_protocol.swift
5-
6-
// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -I %t %s
7-
// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -enable-resilience -I %t %s
8-
9-
// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -I %t %s
10-
// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -enable-resilience -I %t %s
11-
12-
import resilient_struct
13-
import resilient_protocol
14-
15-
// Size is not @_fixed_layout, so we cannot define a new designated initializer
16-
extension Size {
17-
init(ww: Int, hh: Int) {
18-
self.w = ww
19-
self.h = hh // expected-error {{'let' property 'h' may not be initialized directly; use "self.init(...)" or "self = ..." instead}}
20-
}
21-
22-
// This is OK
23-
init(www: Int, hhh: Int) {
24-
self.init(w: www, h: hhh)
25-
}
26-
27-
// This is OK
28-
init(other: Size) {
29-
self = other
30-
}
31-
}
4+
// There should be no errors when run without resilience enabled.
5+
// RUN: %target-swift-frontend -typecheck -swift-version 4 %s
6+
// RUN: %target-swift-frontend -typecheck -swift-version 5 %s
327

338
// Animal is not @_fixed_layout, so we cannot define an @_inlineable
349
// designated initializer
@@ -86,10 +61,3 @@ extension Gadget {
8661
self.init()
8762
}
8863
}
89-
90-
// Protocol extension initializers are OK too
91-
extension OtherResilientProtocol {
92-
public init(other: Self) {
93-
self = other
94-
}
95-
}

0 commit comments

Comments
 (0)