Skip to content

Commit 7d6ab8c

Browse files
committed
Concurrency: silence some -Wcast-function-type-mismatch warnings
The C++ standard does not guarantee that the code and data pointers are interchangeable. Recent enhancements to clang now properly identify the improper `reinterpret_cast` between function types. Silence the warning by switching to `std::bit_cast`. Unfortunately, this is a C++20 feature and we are still on C++17. In the case that the compiler doesn't have a `bit_cast` implementation, fallback with some UB to a local definition.
1 parent d5a6ff2 commit 7d6ab8c

File tree

3 files changed

+67
-13
lines changed

3 files changed

+67
-13
lines changed

stdlib/public/Concurrency/AsyncLet.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,24 @@
3535

3636
#include <new>
3737

38+
#if __cplusplus < 202002l || !defined(__cpp_lib_bit_cast)
39+
namespace std {
40+
template <typename Destination, typename Source>
41+
std::enable_if_t<sizeof(Destination) == sizeof(Source) &&
42+
std::is_trivially_copyable_v<Source> &&
43+
std::is_trivially_copyable_v<Destination>, Destination>
44+
bit_cast(const Source &src) noexcept {
45+
static_assert(std::is_trivially_constructible_v<Destination>,
46+
"The destination type must be trivially constructible");
47+
Destination dst;
48+
std::memcpy(&dst, &src, sizeof(Destination));
49+
return dst;
50+
}
51+
}
52+
#else
53+
#include <bit>
54+
#endif
55+
3856
using namespace swift;
3957

4058
namespace {
@@ -287,8 +305,8 @@ static void _asyncLet_get_throwing_continuation(
287305
}
288306

289307
// Continue the caller's execution.
290-
auto throwingResume
291-
= reinterpret_cast<ThrowingTaskFutureWaitContinuationFunction*>(callContext->ResumeParent);
308+
auto throwingResume =
309+
std::bit_cast<ThrowingTaskFutureWaitContinuationFunction*>(callContext->ResumeParent);
292310
return throwingResume(callContext->Parent, error);
293311
}
294312

@@ -305,8 +323,8 @@ static void swift_asyncLet_get_throwingImpl(
305323
}
306324

307325
auto aletContext = static_cast<AsyncLetContinuationContext*>(callContext);
308-
aletContext->ResumeParent
309-
= reinterpret_cast<TaskContinuationFunction*>(resumeFunction);
326+
aletContext->ResumeParent =
327+
std::bit_cast<TaskContinuationFunction*>(resumeFunction);
310328
aletContext->Parent = callerContext;
311329
aletContext->alet = alet;
312330
auto futureContext = asImpl(alet)->getFutureContext();
@@ -376,7 +394,7 @@ static void asyncLet_finish_after_task_completion(SWIFT_ASYNC_CONTEXT AsyncConte
376394
swift_task_dealloc(task);
377395
}
378396

379-
return reinterpret_cast<ThrowingTaskFutureWaitContinuationFunction*>(resumeFunction)
397+
return std::bit_cast<ThrowingTaskFutureWaitContinuationFunction*>(resumeFunction)
380398
(callerContext, error);
381399
}
382400

@@ -528,14 +546,14 @@ static void swift_asyncLet_consume_throwingImpl(
528546
if (asImpl(alet)->hasResultInBuffer()) {
529547
return asyncLet_finish_after_task_completion(callerContext,
530548
alet,
531-
reinterpret_cast<TaskContinuationFunction*>(resumeFunction),
549+
std::bit_cast<TaskContinuationFunction*>(resumeFunction),
532550
callContext,
533551
nullptr);
534552
}
535553

536554
auto aletContext = static_cast<AsyncLetContinuationContext*>(callContext);
537-
aletContext->ResumeParent
538-
= reinterpret_cast<TaskContinuationFunction*>(resumeFunction);
555+
aletContext->ResumeParent =
556+
std::bit_cast<TaskContinuationFunction*>(resumeFunction);
539557
aletContext->Parent = callerContext;
540558
aletContext->alet = alet;
541559
auto futureContext = asImpl(alet)->getFutureContext();

stdlib/public/Concurrency/DispatchGlobalExecutor.cpp

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,24 @@
5454
#include "ExecutorImpl.h"
5555
#include "TaskPrivate.h"
5656

57+
#if __cplusplus < 202002l || !defined(__cpp_lib_bit_cast)
58+
namespace std {
59+
template <typename Destination, typename Source>
60+
std::enable_if_t<sizeof(Destination) == sizeof(Source) &&
61+
std::is_trivially_copyable_v<Source> &&
62+
std::is_trivially_copyable_v<Destination>, Destination>
63+
bit_cast(const Source &src) noexcept {
64+
static_assert(std::is_trivially_constructible_v<Destination>,
65+
"The destination type must be trivially constructible");
66+
Destination dst;
67+
std::memcpy(&dst, &src, sizeof(Destination));
68+
return dst;
69+
}
70+
}
71+
#else
72+
#include <bit>
73+
#endif
74+
5775
using namespace swift;
5876

5977
// Ensure that Job's layout is compatible with what Dispatch expects.
@@ -119,11 +137,11 @@ static void initializeDispatchEnqueueFunc(dispatch_queue_t queue, void *obj,
119137
if (SWIFT_RUNTIME_WEAK_CHECK(dispatch_async_swift_job))
120138
func = SWIFT_RUNTIME_WEAK_USE(dispatch_async_swift_job);
121139
#elif defined(_WIN32)
122-
func = reinterpret_cast<dispatchEnqueueFuncType>(
140+
func = std::bit_cast<dispatchEnqueueFuncType>(
123141
GetProcAddress(LoadLibraryW(L"dispatch.dll"),
124142
"dispatch_async_swift_job"));
125143
#else
126-
func = reinterpret_cast<dispatchEnqueueFuncType>(
144+
func = std::bit_cast<dispatchEnqueueFuncType>(
127145
dlsym(RTLD_NEXT, "dispatch_async_swift_job"));
128146
#endif
129147
#endif

stdlib/public/Concurrency/TaskGroup.cpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,24 @@
6161
#include <dlfcn.h>
6262
#endif
6363

64+
#if __cplusplus < 202002l || !defined(__cpp_lib_bit_cast)
65+
namespace std {
66+
template <typename Destination, typename Source>
67+
std::enable_if_t<sizeof(Destination) == sizeof(Source) &&
68+
std::is_trivially_copyable_v<Source> &&
69+
std::is_trivially_copyable_v<Destination>, Destination>
70+
bit_cast(const Source &src) noexcept {
71+
static_assert(std::is_trivially_constructible_v<Destination>,
72+
"The destination type must be trivially constructible");
73+
Destination dst;
74+
std::memcpy(&dst, &src, sizeof(Destination));
75+
return dst;
76+
}
77+
}
78+
#else
79+
#include <bit>
80+
#endif
81+
6482
using namespace swift;
6583

6684
#if 0
@@ -1653,7 +1671,7 @@ task_group_wait_resume_adapter(SWIFT_ASYNC_CONTEXT AsyncContext *_context) {
16531671

16541672
auto context = static_cast<TaskFutureWaitAsyncContext *>(_context);
16551673
auto resumeWithError =
1656-
reinterpret_cast<AsyncVoidClosureResumeEntryPoint *>(context->ResumeParent);
1674+
std::bit_cast<AsyncVoidClosureResumeEntryPoint *>(context->ResumeParent);
16571675
return resumeWithError(context->Parent, context->errorResult);
16581676
}
16591677

@@ -1705,7 +1723,7 @@ static void swift_taskGroup_wait_next_throwingImpl(
17051723

17061724
auto context = static_cast<TaskFutureWaitAsyncContext *>(rawContext);
17071725
context->ResumeParent =
1708-
reinterpret_cast<TaskContinuationFunction *>(resumeFunction);
1726+
std::bit_cast<TaskContinuationFunction *>(resumeFunction);
17091727
context->Parent = callerContext;
17101728
context->errorResult = nullptr;
17111729
context->successResultPointer = resultPointer;
@@ -1937,7 +1955,7 @@ void TaskGroupBase::waitAll(SwiftError* bodyError, AsyncTask *waitingTask,
19371955

19381956
auto context = static_cast<TaskFutureWaitAsyncContext *>(rawContext);
19391957
context->ResumeParent =
1940-
reinterpret_cast<TaskContinuationFunction *>(resumeFunction);
1958+
std::bit_cast<TaskContinuationFunction *>(resumeFunction);
19411959
context->Parent = callerContext;
19421960
context->errorResult = nullptr;
19431961
context->successResultPointer = resultPointer;

0 commit comments

Comments
 (0)