Skip to content

Fix default arguments of inlinable local functions #31541

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
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
7 changes: 7 additions & 0 deletions lib/AST/DeclContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,13 @@ swift::FragileFunctionKindRequest::evaluate(Evaluator &evaluator,
auto *VD = cast<ValueDecl>(dc->getAsDecl());
assert(VD->hasParameterList());

if (VD->getDeclContext()->isLocalContext()) {
auto kind = VD->getDeclContext()->getFragileFunctionKind();
if (kind.kind != FragileFunctionKind::None)
return {FragileFunctionKind::DefaultArgument,
kind.allowUsableFromInline};
}

auto effectiveAccess =
VD->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/true);
Expand Down
16 changes: 10 additions & 6 deletions lib/SIL/IR/SILDeclRef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -442,12 +442,9 @@ bool SILDeclRef::isTransparent() const {

/// True if the function should have its body serialized.
IsSerialized_t SILDeclRef::isSerialized() const {
DeclContext *dc;
if (auto closure = getAbstractClosureExpr()) {
dc = closure->getLocalContext();

// Otherwise, ask the AST if we're inside an @inlinable context.
if (dc->getResilienceExpansion() == ResilienceExpansion::Minimal) {
// Ask the AST if we're inside an @inlinable context.
if (closure->getResilienceExpansion() == ResilienceExpansion::Minimal) {
if (isForeign)
return IsSerializable;

Expand All @@ -465,6 +462,13 @@ IsSerialized_t SILDeclRef::isSerialized() const {
// Default argument generators are serialized if the containing
// declaration is public.
if (isDefaultArgGenerator()) {
// Ask the AST if we're inside an @inlinable context.
if (d->getDeclContext()->getResilienceExpansion()
== ResilienceExpansion::Minimal) {
return IsSerialized;
}

// Otherwise, check if the owning declaration is public.
auto scope =
d->getFormalAccessScope(/*useDC=*/nullptr,
/*treatUsableFromInlineAsPublic=*/true);
Expand All @@ -490,7 +494,7 @@ IsSerialized_t SILDeclRef::isSerialized() const {

// Note: if 'd' is a function, then 'dc' is the function itself, not
// its parent context.
dc = d->getInnermostDeclContext();
auto *dc = d->getInnermostDeclContext();

// Local functions are serializable if their parent function is
// serializable.
Expand Down
13 changes: 13 additions & 0 deletions test/SILGen/default_arguments_local.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,16 @@ class ArtClass<T> {
return 0
}
}

// Default arguments of local functions inside @inlinable contexts should be serialized.
// https://bugs.swift.org/browse/SR-12404

// CHECK-LABEL: sil [serialized] [ossa] @$s23default_arguments_local5outeryyF : $@convention(thin) () -> () {
@inlinable public func outer() {
// CHECK-LABEL: sil shared [serialized] [ossa] @$s23default_arguments_local5outeryyF5innerL_1xySi_tFfA_ : $@convention(thin) () -> Int {

// CHECK-LABEL: sil shared [serializable] [ossa] @$s23default_arguments_local5outeryyF5innerL_1xySi_tF : $@convention(thin) (Int) -> () {
func inner(x: Int = 0) {}

inner()
}
17 changes: 15 additions & 2 deletions test/attr/attr_inlinable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@
// expected-warning@-1 {{'@inlinable' declaration is already '@usableFromInline'}}

private func privateFunction() {}
// expected-note@-1{{global function 'privateFunction()' is not '@usableFromInline' or public}}
// expected-note@-1 2{{global function 'privateFunction()' is not '@usableFromInline' or public}}
fileprivate func fileprivateFunction() {}
// expected-note@-1{{global function 'fileprivateFunction()' is not '@usableFromInline' or public}}
func internalFunction() {}
// expected-note@-1{{global function 'internalFunction()' is not '@usableFromInline' or public}}
// expected-note@-1 2{{global function 'internalFunction()' is not '@usableFromInline' or public}}
@usableFromInline func versionedFunction() {}
public func publicFunction() {}

Expand Down Expand Up @@ -306,3 +306,16 @@ public struct PrivateInlinableCrash {
value ? "YES" : "NO"
}
}

// https://bugs.swift.org/browse/SR-12404
@inlinable public func inlinableOuterFunction() {
func innerFunction1(x: () = privateFunction()) {}
// expected-error@-1 {{global function 'privateFunction()' is private and cannot be referenced from a default argument value}}

func innerFunction2(x: () = internalFunction()) {}
// expected-error@-1 {{global function 'internalFunction()' is internal and cannot be referenced from a default argument value}}

func innerFunction3(x: () = versionedFunction()) {}

func innerFunction4(x: () = publicFunction()) {}
}