Skip to content

Commit 433ca8e

Browse files
authored
Merge pull request #80516 from mikeash/function-cast
[Runtime] Add function_cast, switch from std::bit_cast.
2 parents ecb745e + 185b739 commit 433ca8e

10 files changed

+75
-65
lines changed

include/swift/Basic/Casting.h

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//===--- Casting.h - Helpers for casting ------------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_BASIC_CASTING_H
14+
#define SWIFT_BASIC_CASTING_H
15+
16+
#include <type_traits>
17+
18+
namespace swift {
19+
20+
/// Cast between two function types. Use in place of std::bit_cast, which
21+
/// doesn't work on ARM64e with address-discriminated signed function types.
22+
///
23+
/// Address-discriminated ptrauth attributes can only be applied to values with
24+
/// a defined storage location, such as struct fields, since their value is
25+
/// inherently tied to their address. They can't be applied to function
26+
/// paremeters. When passing such a value to a templated function, the ptrauth
27+
/// attribute disappears from the inferred type.
28+
///
29+
/// bit_cast takes the source by reference, which means that the ptrauth
30+
/// attribute remains on the inferred type, and the value is not trivially
31+
/// copyable.
32+
///
33+
/// function_cast instead takes the source by value, avoiding that issue and
34+
/// ensuring that passed-in function pointers are always trivially copyable.
35+
template <typename Destination, typename Source>
36+
Destination function_cast(Source source) {
37+
static_assert(sizeof(Destination) == sizeof(Source),
38+
"Source and destination must be the same size");
39+
static_assert(std::is_trivially_copyable_v<Source>,
40+
"The source type must be trivially constructible");
41+
static_assert(std::is_trivially_copyable_v<Destination>,
42+
"The destination type must be trivially constructible");
43+
44+
Destination destination;
45+
memcpy(&destination, &source, sizeof(source));
46+
return destination;
47+
}
48+
49+
}
50+
51+
#endif

include/swift/Runtime/STLCompatibility.h

-45
This file was deleted.

stdlib/public/Concurrency/AsyncLet.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@
2424
#include "swift/ABI/Metadata.h"
2525
#include "swift/ABI/Task.h"
2626
#include "swift/ABI/TaskOptions.h"
27+
#include "swift/Basic/Casting.h"
2728
#include "swift/Runtime/Heap.h"
2829
#include "swift/Runtime/HeapObject.h"
29-
#include "swift/Runtime/STLCompatibility.h"
3030
#include "swift/Threading/Mutex.h"
3131
#include "llvm/ADT/PointerIntPair.h"
3232

@@ -289,7 +289,7 @@ static void _asyncLet_get_throwing_continuation(
289289

290290
// Continue the caller's execution.
291291
auto throwingResume =
292-
std::bit_cast<ThrowingTaskFutureWaitContinuationFunction*>(callContext->ResumeParent);
292+
function_cast<ThrowingTaskFutureWaitContinuationFunction*>(callContext->ResumeParent);
293293
return throwingResume(callContext->Parent, error);
294294
}
295295

@@ -307,7 +307,7 @@ static void swift_asyncLet_get_throwingImpl(
307307

308308
auto aletContext = static_cast<AsyncLetContinuationContext*>(callContext);
309309
aletContext->ResumeParent =
310-
std::bit_cast<TaskContinuationFunction*>(resumeFunction);
310+
function_cast<TaskContinuationFunction*>(resumeFunction);
311311
aletContext->Parent = callerContext;
312312
aletContext->alet = alet;
313313
auto futureContext = asImpl(alet)->getFutureContext();
@@ -377,7 +377,7 @@ static void asyncLet_finish_after_task_completion(SWIFT_ASYNC_CONTEXT AsyncConte
377377
swift_task_dealloc(task);
378378
}
379379

380-
return std::bit_cast<ThrowingTaskFutureWaitContinuationFunction*>(resumeFunction)
380+
return function_cast<ThrowingTaskFutureWaitContinuationFunction*>(resumeFunction)
381381
(callerContext, error);
382382
}
383383

@@ -529,14 +529,14 @@ static void swift_asyncLet_consume_throwingImpl(
529529
if (asImpl(alet)->hasResultInBuffer()) {
530530
return asyncLet_finish_after_task_completion(callerContext,
531531
alet,
532-
std::bit_cast<TaskContinuationFunction*>(resumeFunction),
532+
function_cast<TaskContinuationFunction*>(resumeFunction),
533533
callContext,
534534
nullptr);
535535
}
536536

537537
auto aletContext = static_cast<AsyncLetContinuationContext*>(callContext);
538538
aletContext->ResumeParent =
539-
std::bit_cast<TaskContinuationFunction*>(resumeFunction);
539+
function_cast<TaskContinuationFunction*>(resumeFunction);
540540
aletContext->Parent = callerContext;
541541
aletContext->alet = alet;
542542
auto futureContext = asImpl(alet)->getFutureContext();

stdlib/public/Concurrency/DispatchGlobalExecutor.cpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@
3030

3131
#include <cstddef>
3232

33+
#include "swift/Basic/Casting.h"
3334
#include "swift/Runtime/Concurrency.h"
3435
#include "swift/Runtime/EnvironmentVariables.h"
35-
#include "swift/Runtime/STLCompatibility.h"
3636

3737
#if SWIFT_CONCURRENCY_ENABLE_DISPATCH
3838
#include "swift/Runtime/HeapObject.h"
@@ -99,11 +99,11 @@ static void initializeDispatchEnqueueFunc(dispatch_queue_t queue, void *obj,
9999
if (SWIFT_RUNTIME_WEAK_CHECK(dispatch_async_swift_job))
100100
func = SWIFT_RUNTIME_WEAK_USE(dispatch_async_swift_job);
101101
#elif defined(_WIN32)
102-
func = std::bit_cast<dispatchEnqueueFuncType>(
102+
func = function_cast<dispatchEnqueueFuncType>(
103103
GetProcAddress(LoadLibraryW(L"dispatch.dll"),
104104
"dispatch_async_swift_job"));
105105
#else
106-
func = std::bit_cast<dispatchEnqueueFuncType>(
106+
func = function_cast<dispatchEnqueueFuncType>(
107107
dlsym(RTLD_NEXT, "dispatch_async_swift_job"));
108108
#endif
109109
#endif

stdlib/public/Concurrency/Task.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "swift/ABI/Metadata.h"
3131
#include "swift/ABI/Task.h"
3232
#include "swift/ABI/TaskOptions.h"
33+
#include "swift/Basic/Casting.h"
3334
#include "swift/Basic/Lazy.h"
3435
#include "swift/Runtime/Concurrency.h"
3536
#include "swift/Runtime/EnvironmentVariables.h"
@@ -1075,19 +1076,19 @@ swift_task_create_commonImpl(size_t rawTaskCreateFlags,
10751076
// The final funclet shouldn't release the task or the task function.
10761077
} else if (asyncLet) {
10771078
initialContext->ResumeParent =
1078-
reinterpret_cast<TaskContinuationFunction*>(&completeTask);
1079+
function_cast<TaskContinuationFunction *>(&completeTask);
10791080

10801081
// If we have a non-null closure context and the task function is not
10811082
// consumed by calling it, use a final funclet that releases both the
10821083
// task and the closure context.
10831084
} else if (closureContext && !taskCreateFlags.isTaskFunctionConsumed()) {
10841085
initialContext->ResumeParent =
1085-
reinterpret_cast<TaskContinuationFunction*>(&completeTaskWithClosure);
1086+
function_cast<TaskContinuationFunction *>(&completeTaskWithClosure);
10861087

10871088
// Otherwise, just release the task.
10881089
} else {
10891090
initialContext->ResumeParent =
1090-
reinterpret_cast<TaskContinuationFunction*>(&completeTaskAndRelease);
1091+
function_cast<TaskContinuationFunction *>(&completeTaskAndRelease);
10911092
}
10921093
#pragma clang diagnostic pop
10931094

stdlib/public/Concurrency/TaskGroup.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@
2727
#include "swift/ABI/Task.h"
2828
#include "swift/ABI/TaskGroup.h"
2929
#include "swift/ABI/TaskOptions.h"
30+
#include "swift/Basic/Casting.h"
3031
#include "swift/Basic/RelativePointer.h"
3132
#include "swift/Basic/STLExtras.h"
3233
#include "swift/Runtime/Concurrency.h"
3334
#include "swift/Runtime/Config.h"
3435
#include "swift/Runtime/Heap.h"
3536
#include "swift/Runtime/HeapObject.h"
36-
#include "swift/Runtime/STLCompatibility.h"
3737
#include "swift/Threading/Mutex.h"
3838
#include <atomic>
3939
#include <deque>
@@ -1661,7 +1661,7 @@ task_group_wait_resume_adapter(SWIFT_ASYNC_CONTEXT AsyncContext *_context) {
16611661

16621662
auto context = static_cast<TaskFutureWaitAsyncContext *>(_context);
16631663
auto resumeWithError =
1664-
std::bit_cast<AsyncVoidClosureResumeEntryPoint *>(context->ResumeParent);
1664+
function_cast<AsyncVoidClosureResumeEntryPoint *>(context->ResumeParent);
16651665
return resumeWithError(context->Parent, context->errorResult);
16661666
}
16671667

@@ -1713,7 +1713,7 @@ static void swift_taskGroup_wait_next_throwingImpl(
17131713

17141714
auto context = static_cast<TaskFutureWaitAsyncContext *>(rawContext);
17151715
context->ResumeParent =
1716-
std::bit_cast<TaskContinuationFunction *>(resumeFunction);
1716+
function_cast<TaskContinuationFunction *>(resumeFunction);
17171717
context->Parent = callerContext;
17181718
context->errorResult = nullptr;
17191719
context->successResultPointer = resultPointer;
@@ -1945,7 +1945,7 @@ void TaskGroupBase::waitAll(SwiftError* bodyError, AsyncTask *waitingTask,
19451945

19461946
auto context = static_cast<TaskFutureWaitAsyncContext *>(rawContext);
19471947
context->ResumeParent =
1948-
std::bit_cast<TaskContinuationFunction *>(resumeFunction);
1948+
function_cast<TaskContinuationFunction *>(resumeFunction);
19491949
context->Parent = callerContext;
19501950
context->errorResult = nullptr;
19511951
context->successResultPointer = resultPointer;

stdlib/public/Distributed/DistributedActor.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
#include "swift/ABI/Actor.h"
1818
#include "swift/ABI/Metadata.h"
1919
#include "swift/ABI/Task.h"
20+
#include "swift/Basic/Casting.h"
2021
#include "swift/Runtime/AccessibleFunction.h"
2122
#include "swift/Runtime/Concurrency.h"
22-
#include "swift/Runtime/STLCompatibility.h"
2323

2424
using namespace swift;
2525

@@ -103,7 +103,7 @@ static void swift_distributed_execute_target_resume(
103103
SWIFT_CONTEXT SwiftError *error) {
104104
auto parentCtx = context->Parent;
105105
auto resumeInParent =
106-
std::bit_cast<TargetExecutorSignature::ContinuationType *>(
106+
function_cast<TargetExecutorSignature::ContinuationType *>(
107107
parentCtx->ResumeParent);
108108
swift_task_dealloc(context);
109109
// See `swift_distributed_execute_target` - `parentCtx` in this case
@@ -132,7 +132,7 @@ void swift_distributed_execute_target(
132132
SwiftError *error =
133133
swift_distributed_makeDistributedTargetAccessorNotFoundError();
134134
auto resumeInParent =
135-
std::bit_cast<TargetExecutorSignature::ContinuationType *>(
135+
function_cast<TargetExecutorSignature::ContinuationType *>(
136136
callerContext->ResumeParent);
137137
resumeInParent(callerContext, error);
138138
return;
@@ -150,7 +150,7 @@ void swift_distributed_execute_target(
150150
swift_task_alloc(asyncFnPtr->ExpectedContextSize));
151151

152152
calleeContext->Parent = callerContext;
153-
calleeContext->ResumeParent = std::bit_cast<TaskContinuationFunction *>(
153+
calleeContext->ResumeParent = function_cast<TaskContinuationFunction *>(
154154
&swift_distributed_execute_target_resume);
155155

156156
accessorEntry(calleeContext, argumentDecoder, argumentTypes, resultBuffer,

test/embedded/dependencies-concurrency-custom-executor.swift

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// DEP: _exit
1919
// DEP: _free
2020
// DEP: _malloc
21+
// DEP: _memcpy
2122
// DEP: _memmove
2223
// DEP: _memset
2324
// DEP: _memset_s

test/embedded/dependencies-concurrency.swift

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
// DEP: _exit
1919
// DEP: _free
2020
// DEP: _malloc
21+
// DEP: _memcpy
2122
// DEP: _memmove
2223
// DEP: _memset
2324
// DEP: _memset_s

test/embedded/dependencies-concurrency2.swift

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// DEP: _exit
1717
// DEP: _free
1818
// DEP: _malloc
19+
// DEP: _memcpy
1920
// DEP: _memmove
2021
// DEP: _memset
2122
// DEP: _memset_s

0 commit comments

Comments
 (0)