Skip to content

Commit f175b07

Browse files
committed
Restrict cross-module struct initializers to be delegating
Slava already had most of this in place as a prototype for the restrictions on what's currently spelled '@_fixed_layout'. Tidy it up and make it apply all the time across module boundaries. rdar://problem/34777878
1 parent 6cc22fe commit f175b07

File tree

3 files changed

+55
-48
lines changed

3 files changed

+55
-48
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3674,19 +3674,16 @@ NOTE(resilience_decl_declared_here,
36743674
NOTE(resilience_decl_declared_here_versioned,
36753675
none, "%0 %1 is not '@_versioned' or public", (DescriptiveDeclKind, DeclName))
36763676

3677-
ERROR(designated_init_in_extension_resilient,none,
3678-
"initializer declared in an extension of "
3679-
"non-'@_fixed_layout' type %0 must delegate to another initializer", (Type))
3677+
ERROR(designated_init_in_cross_module_extension,none,
3678+
"initializer for %0 %1 must use \"self.init(...)\" or \"self = ...\" "
3679+
"because it is not in module %2",
3680+
(DescriptiveDeclKind, Type, Identifier))
36803681

36813682
ERROR(designated_init_inlineable_resilient,none,
3682-
"initializer for non-'@_fixed_layout' type %0 is "
3683-
"'%select{@_transparent|@inline(__always)|@_inlineable|%error}1' and must "
3684-
"delegate to another initializer", (Type, unsigned))
3685-
3686-
ERROR(class_designated_init_inlineable_resilient,none,
3687-
"initializer for class %0 is "
3688-
"'%select{@_transparent|@inline(__always)|@_inlineable|%error}1' and must "
3689-
"delegate to another initializer", (Type, unsigned))
3683+
"initializer for %select{non-'@_fixed_layout' struct|class}0 %1 is "
3684+
"'%select{@_transparent|@inline(__always)|@_inlineable|%error}2' and must "
3685+
"delegate to another initializer",
3686+
(bool, Type, /*FragileFunctionKind*/unsigned))
36903687

36913688
ERROR(inlineable_stored_property,
36923689
none, "'@_inlineable' attribute cannot be applied to stored properties", ())

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -136,38 +136,47 @@ bool TypeChecker::diagnoseInlineableDeclRef(SourceLoc loc,
136136
}
137137

138138
void TypeChecker::diagnoseResilientConstructor(ConstructorDecl *ctor) {
139-
auto nominalDecl = ctor->getDeclContext()
140-
->getAsNominalTypeOrNominalTypeExtensionContext();
139+
const DeclContext *containingContext = ctor->getDeclContext();
140+
const NominalTypeDecl *nominalDecl =
141+
containingContext->getAsNominalTypeOrNominalTypeExtensionContext();
141142

142-
// These restrictions only apply to concrete types, and not protocol
143-
// extensions.
144-
if (isa<ProtocolDecl>(nominalDecl))
143+
// These restrictions only apply to structs and classes.
144+
if (isa<ProtocolDecl>(nominalDecl) || isa<EnumDecl>(nominalDecl))
145145
return;
146146

147-
bool isDelegating =
148-
(ctor->getDelegatingOrChainedInitKind(&Diags) ==
149-
ConstructorDecl::BodyInitKind::Delegating);
150-
151-
if (!isDelegating &&
152-
!nominalDecl->hasFixedLayout(ctor->getParentModule(),
153-
ctor->getResilienceExpansion())) {
154-
if (ctor->getResilienceExpansion() == ResilienceExpansion::Minimal) {
155-
// An @_inlineable designated initializer defined in a resilient type
156-
// cannot initialize stored properties directly, and must chain to
157-
// another initializer.
158-
diagnose(ctor->getLoc(),
159-
isa<ClassDecl>(nominalDecl)
160-
? diag::class_designated_init_inlineable_resilient
161-
: diag::designated_init_inlineable_resilient,
162-
nominalDecl->getDeclaredInterfaceType(),
163-
getFragileFunctionKind(ctor));
164-
} else {
165-
// A designated initializer defined on an extension of a resilient
166-
// type from a different resilience domain cannot initialize stored
167-
// properties directly, and must chain to another initializer.
168-
diagnose(ctor->getLoc(),
169-
diag::designated_init_in_extension_resilient,
170-
nominalDecl->getDeclaredInterfaceType());
171-
}
147+
if (ctor->getDelegatingOrChainedInitKind(&Diags) ==
148+
ConstructorDecl::BodyInitKind::Delegating) {
149+
return;
150+
}
151+
152+
// An initializer defined on an extension of a struct from another module
153+
// cannot initialize stored properties directly, and must chain to another
154+
// initializer.
155+
if (isa<ExtensionDecl>(containingContext) &&
156+
nominalDecl->getParentModule() != containingContext->getParentModule()) {
157+
// Classes already can't have designated initializers in extensions, and
158+
// we diagnose this elsewhere.
159+
if (isa<ClassDecl>(nominalDecl))
160+
return;
161+
162+
diagnose(ctor->getLoc(),
163+
diag::designated_init_in_cross_module_extension,
164+
nominalDecl->getDescriptiveKind(),
165+
nominalDecl->getDeclaredInterfaceType(),
166+
nominalDecl->getParentModule()->getName());
167+
return;
168+
}
169+
170+
// Within the module, we're only concerned about inlinable initializers on
171+
// non-fixed-layout types.
172+
if (ctor->getResilienceExpansion() == ResilienceExpansion::Minimal &&
173+
!nominalDecl->hasFixedLayout()) {
174+
// An @_inlineable designated initializer defined in a resilient type
175+
// cannot initialize stored properties directly, and must chain to
176+
// another initializer.
177+
diagnose(ctor->getLoc(), diag::designated_init_inlineable_resilient,
178+
isa<ClassDecl>(nominalDecl),
179+
nominalDecl->getDeclaredInterfaceType(),
180+
getFragileFunctionKind(ctor));
172181
}
173182
}

test/decl/init/resilience.swift

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
import resilient_struct
77
import resilient_protocol
88

9-
// Point is @_fixed_layout -- this is OK
9+
// Even though Point is @_fixed_layout this is not allowed.
1010
extension Point {
1111
init(xx: Int, yy: Int) {
12+
// expected-error@-1 {{initializer for struct 'Point' must use "self.init(...)" or "self = ..." because it is not in module 'resilient_struct'}}
1213
self.x = xx
1314
self.y = yy
1415
}
@@ -17,7 +18,7 @@ extension Point {
1718
// Size is not @_fixed_layout, so we cannot define a new designated initializer
1819
extension Size {
1920
init(ww: Int, hh: Int) {
20-
// expected-error@-1 {{initializer declared in an extension of non-'@_fixed_layout' type 'Size' must delegate to another initializer}}
21+
// expected-error@-1 {{initializer for struct 'Size' must use "self.init(...)" or "self = ..." because it is not in module 'resilient_struct'}}
2122
self.w = ww
2223
self.h = hh
2324
}
@@ -30,7 +31,7 @@ extension Size {
3031
// FIXME: This should be allowed, but Sema doesn't distinguish this
3132
// case from memberwise initialization, and DI explodes the value type
3233
init(other: Size) {
33-
// expected-error@-1 {{initializer declared in an extension of non-'@_fixed_layout' type 'Size' must delegate to another initializer}}
34+
// expected-error@-1 {{initializer for struct 'Size' must use "self.init(...)" or "self = ..." because it is not in module 'resilient_struct'}}
3435
self = other
3536
}
3637
}
@@ -41,17 +42,17 @@ public struct Animal {
4142
public let name: String
4243

4344
@_inlineable public init(name: String) {
44-
// expected-error@-1 {{initializer for non-'@_fixed_layout' type 'Animal' is '@_inlineable' and must delegate to another initializer}}
45+
// expected-error@-1 {{initializer for non-'@_fixed_layout' struct 'Animal' is '@_inlineable' and must delegate to another initializer}}
4546
self.name = name
4647
}
4748

4849
@inline(__always) public init(dog: String) {
49-
// expected-error@-1 {{initializer for non-'@_fixed_layout' type 'Animal' is '@inline(__always)' and must delegate to another initializer}}
50+
// expected-error@-1 {{initializer for non-'@_fixed_layout' struct 'Animal' is '@inline(__always)' and must delegate to another initializer}}
5051
self.name = dog
5152
}
5253

5354
@_transparent public init(cat: String) {
54-
// expected-error@-1 {{initializer for non-'@_fixed_layout' type 'Animal' is '@_transparent' and must delegate to another initializer}}
55+
// expected-error@-1 {{initializer for non-'@_fixed_layout' struct 'Animal' is '@_transparent' and must delegate to another initializer}}
5556
self.name = cat
5657
}
5758

@@ -63,7 +64,7 @@ public struct Animal {
6364
// FIXME: This should be allowed, but Sema doesn't distinguish this
6465
// case from memberwise initialization, and DI explodes the value type
6566
@_inlineable public init(other: Animal) {
66-
// expected-error@-1 {{initializer for non-'@_fixed_layout' type 'Animal' is '@_inlineable' and must delegate to another initializer}}
67+
// expected-error@-1 {{initializer for non-'@_fixed_layout' struct 'Animal' is '@_inlineable' and must delegate to another initializer}}
6768
self = other
6869
}
6970
}

0 commit comments

Comments
 (0)