Skip to content

Commit fc42f51

Browse files
authored
Merge branch 'release/6.2' into pick-task-names-update
2 parents 8d9b732 + 716b660 commit fc42f51

21 files changed

+340
-85
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ let lifetimeDependenceDiagnosticsPass = FunctionPass(
5353
}
5454
}
5555
for instruction in function.instructions {
56-
if let markDep = instruction as? MarkDependenceInst, markDep.isUnresolved {
56+
if let markDep = instruction as? MarkDependenceInstruction, markDep.isUnresolved {
5757
if let lifetimeDep = LifetimeDependence(markDep, context) {
5858
if analyze(dependence: lifetimeDep, context) {
5959
// Note: This promotes the mark_dependence flag but does not invalidate analyses; preserving analyses is good,
@@ -202,12 +202,29 @@ private struct DiagnoseDependence {
202202
// Check that the parameter dependence for this result is the same
203203
// as the current dependence scope.
204204
if let arg = dependence.scope.parentValue as? FunctionArgument,
205-
function.argumentConventions[resultDependsOn: arg.index] != nil {
206-
// The returned value depends on a lifetime that is inherited or
207-
// borrowed in the caller. The lifetime of the argument value
208-
// itself is irrelevant here.
209-
log(" has dependent function result")
210-
return .continueWalk
205+
let argDep = function.argumentConventions[resultDependsOn: arg.index] {
206+
switch argDep {
207+
case .inherit:
208+
if dependence.markDepInst != nil {
209+
// A mark_dependence represents a "borrow" scope. A local borrow scope cannot inherit the caller's dependence
210+
// because the borrow scope depends on the argument value itself, while the caller allows the result to depend
211+
// on a value that the argument was copied from.
212+
break
213+
}
214+
fallthrough
215+
case .scope:
216+
// The returned value depends on a lifetime that is inherited or
217+
// borrowed in the caller. The lifetime of the argument value
218+
// itself is irrelevant here.
219+
log(" has dependent function result")
220+
return .continueWalk
221+
}
222+
// Briefly (April 2025), RawSpan._extracting, Span._extracting, and UTF8Span.span returned a borrowed value that
223+
// depended on a copied argument. Continue to support those interfaces. The implementations were correct but
224+
// needed an explicit _overrideLifetime.
225+
if let sourceFileKind = dependence.function.sourceFileKind, sourceFileKind == .interface {
226+
return .continueWalk
227+
}
211228
}
212229
return .abortWalk
213230
}

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceScopeFixup.swift

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,10 @@ let lifetimeDependenceScopeFixupPass = FunctionPass(
119119
// Recursively sink enclosing end_access, end_borrow, end_apply, and destroy_value. If the scope can be extended
120120
// into the caller, return the function arguments that are the dependency sources.
121121
var scopeExtension = ScopeExtension(localReachabilityCache, context)
122-
let args = scopeExtension.extendScopes(dependence: newLifetimeDep)
122+
guard scopeExtension.extendScopes(dependence: newLifetimeDep) else {
123+
continue
124+
}
125+
let args = scopeExtension.findArgumentDependencies()
123126

124127
// Redirect the dependence base to the function arguments. This may create additional mark_dependence instructions.
125128
markDep.redirectFunctionReturn(to: args, context)
@@ -246,28 +249,25 @@ private struct ScopeExtension {
246249
// `mark_dependence` to the outer access `%0`. This ensures that exclusivity diagnostics correctly reports the
247250
// violation, and that subsequent optimizations do not shrink the inner access `%a1`.
248251
extension ScopeExtension {
249-
mutating func extendScopes(dependence: LifetimeDependence) -> SingleInlineArray<FunctionArgument> {
252+
mutating func extendScopes(dependence: LifetimeDependence) -> Bool {
250253
log("Scope fixup for lifetime dependent instructions: \(dependence)")
251254

252255
gatherExtensions(dependence: dependence)
253256

254-
let noCallerScope = SingleInlineArray<FunctionArgument>()
255-
256257
// computeDependentUseRange initializes scopeExtension.dependsOnCaller.
257258
guard var useRange = computeDependentUseRange(of: dependence) else {
258-
return noCallerScope
259+
return false
259260
}
260261
// tryExtendScopes deinitializes 'useRange'
261262
var scopesToExtend = SingleInlineArray<ExtendableScope>()
262263
guard canExtendScopes(over: &useRange, scopesToExtend: &scopesToExtend) else {
263264
useRange.deinitialize()
264-
return noCallerScope
265+
return false
265266
}
266267
// extend(over:) must receive the original unmodified `useRange`, without intermediate scope ending instructions.
267268
// This deinitializes `useRange` before erasing instructions.
268269
extend(scopesToExtend: scopesToExtend, over: &useRange, context)
269-
270-
return dependsOnArgs
270+
return true
271271
}
272272
}
273273

@@ -448,10 +448,15 @@ extension ScopeExtension {
448448
}
449449

450450
extension ScopeExtension {
451-
/// Return all scope owners as long as they are all function arguments and all nested accesses are compatible with
452-
/// their argument convention. Then, if all nested accesses were extended to the return statement, it is valid to
453-
/// logically combine them into a single access for the purpose of diagnostic lifetime dependence.
454-
var dependsOnArgs: SingleInlineArray<FunctionArgument> {
451+
/// Check if the dependent value depends only on function arguments and can therefore be returned to caller. If so,
452+
/// return the list of arguments that it depends on. If this returns an empty list, then the dependent value cannot be
453+
/// returned.
454+
///
455+
/// The conditions for returning a dependent value are:
456+
/// - The dependent value is returned from this function.
457+
/// - All nested scopes are access scopes that are redundant with the caller's exclusive access scope.
458+
/// - All scope owners are function arguments.
459+
func findArgumentDependencies() -> SingleInlineArray<FunctionArgument> {
455460
let noCallerScope = SingleInlineArray<FunctionArgument>()
456461
// Check that the dependent value is returned by this function.
457462
if !dependsOnCaller! {

SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ extension LifetimeDependence {
161161

162162
// Construct a LifetimeDependence from a return value. This only
163163
// constructs a dependence for ~Escapable results that do not have a
164-
// lifetime dependence (@_unsafeNonescapableResult).
164+
// lifetime dependence (@lifetime(immortal), @_unsafeNonescapableResult).
165165
//
166166
// This is necessary because inserting a mark_dependence placeholder for such an unsafe dependence would illegally
167167
// have the same base and value operand.

lib/AST/LifetimeDependence.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,8 @@ class LifetimeDependenceChecker {
790790
auto immortalParam =
791791
std::find_if(afd->getParameters()->begin(),
792792
afd->getParameters()->end(), [](ParamDecl *param) {
793-
return strcmp(param->getName().get(), "immortal") == 0;
793+
return param->getName().nonempty()
794+
&& strcmp(param->getName().get(), "immortal") == 0;
794795
});
795796
if (immortalParam != afd->getParameters()->end()) {
796797
diagnose(*immortalParam,

stdlib/public/core/Span/RawSpan.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,8 @@ extension RawSpan {
711711
public func _extracting(first maxLength: Int) -> Self {
712712
_precondition(maxLength >= 0, "Can't have a prefix of negative length")
713713
let newCount = min(maxLength, byteCount)
714-
return unsafe Self(_unchecked: _pointer, byteCount: newCount)
714+
let newSpan = unsafe Self(_unchecked: _pointer, byteCount: newCount)
715+
return unsafe _overrideLifetime(newSpan, copying: self)
715716
}
716717

717718
/// Returns a span over all but the given number of trailing bytes.
@@ -734,7 +735,8 @@ extension RawSpan {
734735
_precondition(k >= 0, "Can't drop a negative number of bytes")
735736
let droppedCount = min(k, byteCount)
736737
let count = byteCount &- droppedCount
737-
return unsafe Self(_unchecked: _pointer, byteCount: count)
738+
let newSpan = unsafe Self(_unchecked: _pointer, byteCount: count)
739+
return unsafe _overrideLifetime(newSpan, copying: self)
738740
}
739741

740742
/// Returns a span containing the trailing bytes of the span,

stdlib/public/core/Span/Span.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,8 @@ extension Span where Element: ~Copyable {
764764
public func _extracting(first maxLength: Int) -> Self {
765765
_precondition(maxLength >= 0, "Can't have a prefix of negative length")
766766
let newCount = min(maxLength, count)
767-
return unsafe Self(_unchecked: _pointer, count: newCount)
767+
let newSpan = unsafe Self(_unchecked: _pointer, count: newCount)
768+
return unsafe _overrideLifetime(newSpan, copying: self)
768769
}
769770

770771
/// Returns a span over all but the given number of trailing elements.
@@ -786,7 +787,8 @@ extension Span where Element: ~Copyable {
786787
public func _extracting(droppingLast k: Int) -> Self {
787788
_precondition(k >= 0, "Can't drop a negative number of elements")
788789
let droppedCount = min(k, count)
789-
return unsafe Self(_unchecked: _pointer, count: count &- droppedCount)
790+
let newSpan = unsafe Self(_unchecked: _pointer, count: count &- droppedCount)
791+
return unsafe _overrideLifetime(newSpan, copying: self)
790792
}
791793

792794
/// Returns a span containing the final elements of the span,

stdlib/public/core/UTF8Span.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ extension UTF8Span {
181181
public var span: Span<UInt8> {
182182
@lifetime(copy self)
183183
get {
184-
unsafe Span(_unchecked: _unsafeBaseAddress, count: self.count)
184+
let newSpan = unsafe Span<UInt8>(_unchecked: _unsafeBaseAddress, count: self.count)
185+
return unsafe _overrideLifetime(newSpan, copying: self)
185186
}
186187
}
187188

stdlib/public/runtime/MetadataLookup.cpp

Lines changed: 19 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2907,25 +2907,6 @@ static NodePointer getParameterList(NodePointer funcType) {
29072907
return parameterContainer;
29082908
}
29092909

2910-
static const Metadata *decodeType(TypeDecoder<DecodedMetadataBuilder> &decoder,
2911-
NodePointer type) {
2912-
assert(type->getKind() == Node::Kind::Type);
2913-
2914-
auto builtTypeOrError = decoder.decodeMangledType(type);
2915-
2916-
if (builtTypeOrError.isError()) {
2917-
auto err = builtTypeOrError.getError();
2918-
char *errStr = err->copyErrorString();
2919-
err->freeErrorString(errStr);
2920-
return nullptr;
2921-
}
2922-
2923-
if (!builtTypeOrError.getType().isMetadata())
2924-
return nullptr;
2925-
2926-
return builtTypeOrError.getType().getMetadata();
2927-
}
2928-
29292910
SWIFT_CC(swift)
29302911
SWIFT_RUNTIME_STDLIB_SPI
29312912
unsigned swift_func_getParameterCount(const char *typeNameStart,
@@ -3009,8 +2990,21 @@ swift_func_getParameterTypeInfo(
30092990

30102991
SubstGenericParametersFromMetadata substFn(genericEnv, genericArguments);
30112992

3012-
DecodedMetadataBuilder builder(
3013-
demangler,
2993+
// for each parameter (TupleElement), store it into the provided buffer
2994+
for (unsigned index = 0; index != typesLength; ++index) {
2995+
auto nodePointer = parameterList->getChild(index);
2996+
2997+
if (nodePointer->getKind() == Node::Kind::TupleElement) {
2998+
assert(nodePointer->getNumChildren() == 1);
2999+
nodePointer = nodePointer->getFirstChild();
3000+
}
3001+
assert(nodePointer->getKind() == Node::Kind::Type);
3002+
3003+
auto request = MetadataRequest(MetadataState::Complete);
3004+
3005+
auto typeInfoOrErr = swift_getTypeByMangledNode(
3006+
request, demangler, nodePointer,
3007+
/*arguments=*/genericArguments,
30143008
/*substGenericParam=*/
30153009
[&substFn](unsigned depth, unsigned index) {
30163010
return substFn.getMetadata(depth, index).Ptr;
@@ -3019,24 +3013,13 @@ swift_func_getParameterTypeInfo(
30193013
[&substFn](const Metadata *type, unsigned index) {
30203014
return substFn.getWitnessTable(type, index);
30213015
});
3022-
TypeDecoder<DecodedMetadataBuilder> decoder(builder);
3023-
3024-
// for each parameter (TupleElement), store it into the provided buffer
3025-
for (unsigned index = 0; index != typesLength; ++index) {
3026-
auto *parameter = parameterList->getChild(index);
3027-
3028-
if (parameter->getKind() == Node::Kind::TupleElement) {
3029-
assert(parameter->getNumChildren() == 1);
3030-
parameter = parameter->getFirstChild();
3031-
}
3032-
3033-
assert(parameter->getKind() == Node::Kind::Type);
30343016

3035-
auto type = decodeType(decoder, parameter);
3036-
if (!type)
3017+
if (typeInfoOrErr.isError()) {
30373018
return -3; // Failed to decode a type.
3019+
}
30383020

3039-
types[index] = type;
3021+
auto typeInfo = typeInfoOrErr.getType();
3022+
types[index] = typeInfo.getMetadata();
30403023
} // end foreach parameter
30413024

30423025
return typesLength;

test/Distributed/Runtime/distributed_actor_func_calls_without_touching_returnType_metadata_first.swift

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
// RUN: %empty-directory(%t)
2-
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems -target %target-swift-5.7-abi-triple %S/../Inputs/FakeDistributedActorSystems.swift
32
// RUN: %target-build-swift -module-name dist -target %target-swift-5.7-abi-triple -parse-as-library -j2 -parse-as-library -plugin-path %swift-plugin-dir -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -o %t/a.out
43
// RUN: %target-codesign %t/a.out
5-
// RUN: %target-run %t/a.out
4+
5+
// RUN: %target-run %t/a.out PARAMETER_TYPE
6+
// RUN: %target-run %t/a.out RETURN_TYPE
67

78
// REQUIRES: executable_test
89
// REQUIRES: concurrency
@@ -17,7 +18,6 @@
1718

1819
import Darwin
1920
import Distributed
20-
import FakeDistributedActorSystems
2121
import Foundation
2222

2323
typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem
@@ -1052,20 +1052,39 @@ struct BigGeneric<T>: Codable {
10521052
}
10531053

10541054
distributed actor D {
1055+
public distributed func getBigGeneric(_ value: BigGeneric<TypeXXXX>) {}
10551056
public distributed func getBigGeneric() -> BigGeneric<TypeXXXX> {
1056-
return BigGeneric()
1057-
}
1057+
return BigGeneric()
1058+
}
10581059
}
10591060

1060-
func attempt(n: Int) {
1061-
var fname = "$s4dist1DC13getBigGenericAA0cD0VyAA8Type\(n)VGyF"
1061+
func attempt(_ mode: Mode, n: Int) {
1062+
var funcName_returnType = "$s4dist1DC13getBigGenericAA0cD0VyAA8Type\(n)VGyF"
1063+
var funcName_param = "$s4dist1DC13getBigGenericyyAA0cD0VyAA8Type\(n)VGF"
10621064

10631065
func tryLookup() {
1064-
let t = fname.withUTF8 {
1065-
__getReturnTypeInfo($0.baseAddress!, UInt($0.count), nil, nil)
1066-
}
1066+
let t: (any Any.Type)? =
1067+
switch mode {
1068+
case .returnType:
1069+
funcName_returnType.withUTF8 {
1070+
__getReturnTypeInfo($0.baseAddress!, UInt($0.count), nil, nil)
1071+
}
1072+
1073+
case .paramType:
1074+
funcName_param.withUTF8 { nameBuf in
1075+
var type: Any.Type?
1076+
withUnsafeMutablePointer(to: &type) { typePtr in
1077+
let ret = __getParameterTypeInfo(nameBuf.baseAddress!, UInt(nameBuf.count), nil, nil, typePtr._rawValue, 1)
1078+
if ret != 1 {
1079+
fatalError("Decoded \(ret) parameters, expected 1")
1080+
}
1081+
}
1082+
return type
1083+
}
1084+
}
1085+
10671086
guard let t else {
1068-
print("couldn't look up type for: \(fname)")
1087+
print("couldn't look up type for mode: \(mode)")
10691088
exit(1)
10701089
}
10711090
func examineType<T>(_t: T.Type) {
@@ -1081,10 +1100,23 @@ func attempt(n: Int) {
10811100
}
10821101
}
10831102

1103+
enum Mode: String {
1104+
case returnType = "RETURN_TYPE"
1105+
case paramType = "PARAMETER_TYPE"
1106+
}
1107+
10841108
@main struct Main {
10851109
static func main() {
1110+
if CommandLine.arguments.count < 2 {
1111+
fatalError("Expected explicit mode in command line arguments, was: \(CommandLine.arguments)")
1112+
}
1113+
1114+
let mode = Mode.init(rawValue: CommandLine.arguments.dropFirst().first!)!
1115+
print("Checking in mode: \(mode)...")
1116+
10861117
for i in 1000...1999 {
1087-
attempt(n: i)
1118+
attempt(mode, n: i)
10881119
}
1120+
print("Passed in mode: \(mode)!")
10891121
}
1090-
}
1122+
}

test/SIL/explicit_lifetime_dependence_specifiers.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ func deriveThisOrThat1(_ this: borrowing BufferView, _ that: borrowing BufferVie
105105
if (Int.random(in: 1..<100) == 0) {
106106
return BufferView(independent: this.ptr)
107107
}
108-
return BufferView(independent: that.ptr)
108+
let newThat = BufferView(independent: that.ptr)
109+
return _overrideLifetime(newThat, copying: that)
109110
}
110111

111112
// CHECK-LABEL: sil hidden @$s39explicit_lifetime_dependence_specifiers17deriveThisOrThat2yAA10BufferViewVAD_ADntF : $@convention(thin) (@guaranteed BufferView, @owned BufferView) -> @lifetime(copy 1, borrow 0) @owned BufferView {

test/SIL/implicit_lifetime_dependence.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,14 @@ func testBasic() {
8585
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence6deriveyAA10BufferViewVADF : $@convention(thin) (@guaranteed BufferView) -> @lifetime(copy 0) @owned BufferView {
8686
@lifetime(copy x)
8787
func derive(_ x: borrowing BufferView) -> BufferView {
88-
return BufferView(x.ptr, x.c)
88+
let newBV = BufferView(x.ptr, x.c)
89+
return _overrideLifetime(newBV, copying: x)
8990
}
9091

9192
@lifetime(copy x)
9293
func derive(_ unused: Int, _ x: borrowing BufferView) -> BufferView {
93-
return BufferView(independent: x.ptr, x.c)
94+
let newBV = BufferView(independent: x.ptr, x.c)
95+
return _overrideLifetime(newBV, copying: x)
9496
}
9597

9698
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence16consumeAndCreateyAA10BufferViewVADnF : $@convention(thin) (@owned BufferView) -> @lifetime(copy 0) @owned BufferView {
@@ -212,7 +214,9 @@ struct GenericBufferView<Element> : ~Escapable {
212214
// CHECK-LABEL: sil hidden @$s28implicit_lifetime_dependence23tupleLifetimeDependenceyAA10BufferViewV_ADtADF : $@convention(thin) (@guaranteed BufferView) -> @lifetime(copy 0) (@owned BufferView, @owned BufferView) {
213215
@lifetime(copy x)
214216
func tupleLifetimeDependence(_ x: borrowing BufferView) -> (BufferView, BufferView) {
215-
return (BufferView(x.ptr, x.c), BufferView(x.ptr, x.c))
217+
let newX1 = BufferView(x.ptr, x.c)
218+
let newX2 = BufferView(x.ptr, x.c)
219+
return (_overrideLifetime(newX1, copying: x), _overrideLifetime(newX2, copying: x))
216220
}
217221

218222
public struct OuterNE: ~Escapable {

0 commit comments

Comments
 (0)