Skip to content

Don't force inlinable constructors to delegate in non-resilient code #14721

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5471,7 +5471,11 @@ ConstructorDecl::getDelegatingOrChainedInitKind(DiagnosticEngine *diags,
// always delegating. This occurs if the struct type is not fixed layout,
// and the constructor is either inlinable or defined in another module.
if (Kind == BodyInitKind::None && isa<StructDecl>(NTD)) {
if (NTD->isFormallyResilient() &&
// Note: This is specifically not using isFormallyResilient. We relax this
// rule for structs in non-resilient modules so that they can have inlinable
// constructors, as long as those constructors don't reference private
// declarations.
if (NTD->isResilient() &&
getResilienceExpansion() == ResilienceExpansion::Minimal) {
Kind = BodyInitKind::Delegating;

Expand Down
9 changes: 6 additions & 3 deletions lib/Sema/TypeCheckStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1620,9 +1620,12 @@ bool TypeChecker::typeCheckConstructorBodyUntil(ConstructorDecl *ctor,
}

// An inlinable constructor in a class must always be delegating,
// unless the class is formally '@_fixed_layout'.
if (!isDelegating &&
ClassD->isFormallyResilient() &&
// unless the class is '@_fixed_layout'.
// Note: This is specifically not using isFormallyResilient. We relax this
// rule for classes in non-resilient modules so that they can have inlinable
// constructors, as long as those constructors don't reference private
// declarations.
if (!isDelegating && ClassD->isResilient() &&
ctor->getResilienceExpansion() == ResilienceExpansion::Minimal) {
diagnose(ctor, diag::class_designated_init_inlineable_resilient,
ClassD->getDeclaredInterfaceType(),
Expand Down
38 changes: 38 additions & 0 deletions test/decl/init/resilience-cross-module.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: %empty-directory(%t)

// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../../Inputs/resilient_struct.swift
// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../../Inputs/resilient_protocol.swift

// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -I %t %s
// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -enable-resilience -I %t %s

// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -I %t %s
// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -enable-resilience -I %t %s

import resilient_struct
import resilient_protocol

// Size is not @_fixed_layout, so we cannot define a new designated initializer
extension Size {
init(ww: Int, hh: Int) {
self.w = ww
self.h = hh // expected-error {{'let' property 'h' may not be initialized directly; use "self.init(...)" or "self = ..." instead}}
}

// This is OK
init(www: Int, hhh: Int) {
self.init(w: www, h: hhh)
}

// This is OK
init(other: Size) {
self = other
}
}

// Protocol extension initializers are OK too
extension OtherResilientProtocol {
public init(other: Self) {
self = other
}
}
42 changes: 5 additions & 37 deletions test/decl/init/resilience.swift
Original file line number Diff line number Diff line change
@@ -1,34 +1,9 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -enable-resilience %s -DRESILIENT
// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -enable-resilience %s -DRESILIENT

// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_struct.swiftmodule -module-name=resilient_struct %S/../../Inputs/resilient_struct.swift
// RUN: %target-swift-frontend -emit-module -enable-resilience -emit-module-path=%t/resilient_protocol.swiftmodule -module-name=resilient_protocol %S/../../Inputs/resilient_protocol.swift

// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -I %t %s
// RUN: %target-swift-frontend -typecheck -swift-version 4 -verify -enable-resilience -I %t %s

// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -I %t %s
// RUN: %target-swift-frontend -typecheck -swift-version 5 -verify -enable-resilience -I %t %s

import resilient_struct
import resilient_protocol

// Size is not @_fixed_layout, so we cannot define a new designated initializer
extension Size {
init(ww: Int, hh: Int) {
self.w = ww
self.h = hh // expected-error {{'let' property 'h' may not be initialized directly; use "self.init(...)" or "self = ..." instead}}
}

// This is OK
init(www: Int, hhh: Int) {
self.init(w: www, h: hhh)
}

// This is OK
init(other: Size) {
self = other
}
}
// There should be no errors when run without resilience enabled.
// RUN: %target-swift-frontend -typecheck -swift-version 4 %s
// RUN: %target-swift-frontend -typecheck -swift-version 5 %s

// Animal is not @_fixed_layout, so we cannot define an @_inlineable
// designated initializer
Expand Down Expand Up @@ -86,10 +61,3 @@ extension Gadget {
self.init()
}
}

// Protocol extension initializers are OK too
extension OtherResilientProtocol {
public init(other: Self) {
self = other
}
}