On Sat, Feb 12, 2022 at 12:09 AM Jens Maurer <Jens.Maurer@gmx.net> wrote:
On 11/02/2022 23.54, Corentin wrote:
> Su
>
> On Fri, Feb 11, 2022 at 10:44 PM Jens Maurer <Jens.Maurer@gmx.net <mailto:Jens.Maurer@gmx.net>> wrote:
>
>     On 11/02/2022 22.39, Corentin wrote:
>     >
>     >
>     > On Fri, Feb 11, 2022 at 10:33 PM Jens Maurer <Jens.Maurer@gmx.net <mailto:Jens.Maurer@gmx.net> <mailto:Jens.Maurer@gmx.net <mailto:Jens.Maurer@gmx.net>>> wrote:
>     >
>     >     On 11/02/2022 22.20, Corentin via Liaison wrote:
>     >
>     >     >
>     >     >         I think the most intuitive behavior is if
>     >     >
>     >     >         extern "C" thread_local S foo;
>     >     >
>     >     >         behaves just like _Thread_local would do in C and a C++ type
>     >     >         that requires non-trivial initialization would simply not
>     >     >         be allowed, i.e. it behaves like _Thread_local in clang
>     >     >         in c++ mode.
>     >
>     >     Sounds good to me.
>     >
>     >      - Survives WG14 making thread_local a real keyword.
>     >
>     >      - Requires no collaboration from WG14.
>     >
>     >      - Your header shared between C++ and C already ought to use 'extern "C"',
>     >     so this reduces the footgun surface.
>     >
>     >      - thread_local in C++ with dynamic libraries is already a nightmare
>     >     (dynamic initialization order, squared), and this nicely sidesteps the
>     >     problem.
>     >
>     >      - If C++ wants to do something on the C++ side (e.g. constdestroy or so),
>     >     it can do so at its own pace.
>     >
>     >     >     I agree. Why would you be trying to use a type with non-trivial init in common code defined in a header, but so that it does different things in C and C++? If you need non-trivial init, define the code in a separate C++ transition unit, not in a header.
>     >     >
>     >     >
>     >     > But by that logic, do we want to change the grammar of C++ for this narrow scenario?
>     >
>     >     We're not changing the grammar.  We're just adding a paragraph of restrictions
>     >     for thread_local.  That seems palatable, given that 'extern "C"' already
>     >     causes restrictions for other areas of the C++ syntax.
>     >
>     >
>     > Don't we need to allow extern "C" static? Afaict this would be novel
>
>     extern "C" {
>       static int x = 1;
>     }
>
>     works with gcc today.
>
>
> How do you handle local static at function scope?
If you want to use the surrounding function from both C and C++,
you need to wrap it into "extern C" (simply to get the correct name
mangling) and the thread_local thus appears within extern C and the
novel semantics apply.

If you want to use the function from C++ only, it's likely not wrapped
in "extern C" and you get the usual C++ semantics.

My understanding of the issue was as follows:
There is a thread_local which is a C++ type (thereby not extern) , passed to a C function, from within a C++ function.
Such thread_local could be declared at function scope.

struct S {
S();
};

extern "C" {
void foo(S*);
static thread_local S s; // would be okay, with different semantics (eager initialization)
};


void f() {
/* extern "C" */ static thread_local S s; // Do we care to support that ?
foo(&s);
}


Here I don't think users will necessarily want to put f in the extern "C" scope, for example.
The variable needs to be in an extern "C" scope, not necessarily the enclosing function


Jens