On Sat, 14 Jun 2025, Jeremy Drake via Cygwin wrote:

> Consider the following -std=c++20:
> #include <pthread.h>
>
> constinit pthread_mutex_t foo = PTHREAD_MUTEX_INITIALIZER;
>
> With g++ 12.4.0, this succeeds, but with clang 20.1.6 it fails:
> pthreadtest.cpp:3:27: error: variable does not have a constant initializer
>     3 | constinit pthread_mutex_t foo = PTHREAD_MUTEX_INITIALIZER;
>       |                           ^     ~~~~~~~~~~~~~~~~~~~~~~~~~
> pthreadtest.cpp:3:1: note: required by 'constinit' specifier here
>     3 | constinit pthread_mutex_t foo = PTHREAD_MUTEX_INITIALIZER;
>       | ^~~~~~~~~
> pthreadtest.cpp:3:33: note: cast that performs the conversions of a 
> reinterpret_cast is not allowed in a constant expression
>     3 | constinit pthread_mutex_t foo = PTHREAD_MUTEX_INITIALIZER;
>       |                                 ^
> /usr/include/pthread.h:49:35: note: expanded from macro 
> 'PTHREAD_MUTEX_INITIALIZER'
>    49 | #define PTHREAD_MUTEX_INITIALIZER PTHREAD_NORMAL_MUTEX_INITIALIZER_NP
>       |                                   ^
> /usr/include/pthread.h:47:45: note: expanded from macro 
> 'PTHREAD_NORMAL_MUTEX_INITIALIZER_NP'
>    47 | #define PTHREAD_NORMAL_MUTEX_INITIALIZER_NP (pthread_mutex_t)19
>       |                                             ^
> 1 error generated.
>
> It seems the standard disallows this sort of cast pretty comprehensively.
> Is there some way that Cygwin's pthread initializer macros can be made
> compatible with constinit?

I was thinking changing the typedef to be uintptr_t instead of a pointer
would allow constinit initialization to a constant integer, and be the
same ABI-wise, but it would probably change C++ mangled names for
functions taking those types as parameters.

What did work for me, and I'll admit it's pretty gross, is

#include <pthread.h>

#ifdef __i386__
#define SYMPREFIX "_"
#else
#define SYMPREFIX ""
#endif
__asm__( SYMPREFIX "__pthread_normal_mutex_initializer_np=19");

extern "C" struct __pthread_mutex_t __pthread_normal_mutex_initializer_np;

#undef PTHREAD_NORMAL_MUTEX_INITIALIZER_NP
#define PTHREAD_NORMAL_MUTEX_INITIALIZER_NP 
(&__pthread_normal_mutex_initializer_np)

constinit pthread_mutex_t foo = PTHREAD_MUTEX_INITIALIZER;

Basically, hiding the value from the compiler and making it think it is
in fact dealing with a real pointer.

-- 
Problem reports:      https://cygwin.com/problems.html
FAQ:                  https://cygwin.com/faq/
Documentation:        https://cygwin.com/docs.html
Unsubscribe info:     https://cygwin.com/ml/#unsubscribe-simple

Reply via email to