Skip to content

Commit 54651d1

Browse files
authored
Merge pull request #82473 from atrick/62-explicit-init
[6.2] Disable surprising lifetime inference of implicit initializers
2 parents 9220e68 + 78e8b5a commit 54651d1

File tree

4 files changed

+62
-6
lines changed

4 files changed

+62
-6
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8294,6 +8294,9 @@ ERROR(lifetime_dependence_cannot_infer_kind, none,
82948294
ERROR(lifetime_dependence_cannot_infer_scope_ownership, none,
82958295
"cannot borrow the lifetime of '%0', which has consuming ownership on %1",
82968296
(StringRef, StringRef))
8297+
ERROR(lifetime_dependence_cannot_infer_implicit_init, none,
8298+
"cannot infer implicit initialization lifetime. Add an initializer with "
8299+
"'@_lifetime(...)' for each parameter the result depends on", ())
82978300

82988301
//------------------------------------------------------------------------------
82998302
// MARK: Lifetime Dependence Experimental Inference

lib/AST/LifetimeDependence.cpp

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,9 +1064,13 @@ class LifetimeDependenceChecker {
10641064
return LifetimeDependenceKind::Scope;
10651065
}
10661066

1067-
// Infer implicit initialization. The dependence kind can be inferred, similar
1068-
// to an implicit setter, because the implementation is simply an assignment
1069-
// to stored property.
1067+
// Infer implicit initialization. A non-Escapable initializer parameter can
1068+
// always be inferred, similar to an implicit setter, because the
1069+
// implementation is simply an assignment to stored property. Escapable
1070+
// parameters are ambiguous: they may either be borrowed or
1071+
// non-dependent. non-Escapable types often have incidental integer fields
1072+
// that are unrelated to lifetime. Avoid inferring any dependency on Escapable
1073+
// parameters unless it is the (unambiguously borrowed) sole parameter.
10701074
void inferImplicitInit() {
10711075
auto *afd = cast<AbstractFunctionDecl>(decl);
10721076
if (afd->getParameters()->size() == 0) {
@@ -1086,15 +1090,28 @@ class LifetimeDependenceChecker {
10861090
if (paramTypeInContext->hasError()) {
10871091
return;
10881092
}
1093+
if (!paramTypeInContext->isEscapable()) {
1094+
// An implicitly initialized non-Escapable value always copies its
1095+
// dependency.
1096+
targetDeps = std::move(targetDeps).add(paramIndex,
1097+
LifetimeDependenceKind::Inherit);
1098+
continue;
1099+
}
1100+
if (afd->getParameters()->size() > 1 && !useLazyInference()) {
1101+
diagnose(param->getLoc(),
1102+
diag::lifetime_dependence_cannot_infer_implicit_init);
1103+
return;
1104+
}
1105+
// A single Escapable parameter must be borrowed.
10891106
auto kind = inferLifetimeDependenceKind(paramTypeInContext,
10901107
param->getValueOwnership());
10911108
if (!kind) {
10921109
diagnose(returnLoc,
10931110
diag::lifetime_dependence_cannot_infer_scope_ownership,
10941111
param->getParameterName().str(), diagnosticQualifier());
1095-
return;
10961112
}
1097-
targetDeps = std::move(targetDeps).add(paramIndex, *kind);
1113+
targetDeps = std::move(targetDeps).add(paramIndex,
1114+
LifetimeDependenceKind::Scope);
10981115
}
10991116
pushDeps(std::move(targetDeps));
11001117
}

test/Sema/lifetime_attr.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func immortalConflict(_ immortal: Int) -> NE { // expected-error{{conflict betwe
7575
}
7676

7777
do {
78-
struct Test: ~Escapable {
78+
struct Test: ~Escapable { // expected-error{{cannot infer implicit initialization lifetime. Add an initializer with '@_lifetime(...)' for each parameter the result depends on}}
7979
var v1: Int
8080
var v2: NE
8181
}

test/Sema/lifetime_depend_infer.swift

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,3 +577,39 @@ struct NonEscapableMutableSelf: ~Escapable {
577577
@_lifetime(&self)
578578
mutating func mutatingMethodOneParamBorrow(_: NE) {}
579579
}
580+
581+
// =============================================================================
582+
// Initializers
583+
// =============================================================================
584+
585+
struct NE_Int: ~Escapable {
586+
let i: Int
587+
}
588+
589+
struct NE_C: ~Escapable { // expected-error{{cannot borrow the lifetime of 'c', which has consuming ownership on an implicit initializer}}
590+
let c: C
591+
}
592+
593+
struct NE_C_Int: ~Escapable { // expected-error{{cannot infer implicit initialization lifetime. Add an initializer with '@_lifetime(...)' for each parameter the result depends on}}
594+
let c: C
595+
let i: Int
596+
}
597+
598+
struct NE_Int_Int: ~Escapable { // expected-error{{cannot infer implicit initialization lifetime. Add an initializer with '@_lifetime(...)' for each parameter the result depends on}}
599+
let i: Int
600+
let j: Int
601+
}
602+
603+
struct NE_NE: ~Escapable {
604+
let ne: NE
605+
}
606+
607+
struct NE_NE_Int: ~Escapable { // expected-error{{cannot infer implicit initialization lifetime. Add an initializer with '@_lifetime(...)' for each parameter the result depends on}}
608+
let ne: NE
609+
let i: Int
610+
}
611+
612+
struct NE_NE_C: ~Escapable { // expected-error{{cannot infer implicit initialization lifetime. Add an initializer with '@_lifetime(...)' for each parameter the result depends on}}
613+
let ne: NE
614+
let c: C
615+
}

0 commit comments

Comments
 (0)