I think i was very missguided in today's call
Let me think if I can clarify the different scenario
for a thread_local of type S
- If S is incomplete the program is ill-formed
- If S has an incomplete destructor or constructor, or if S has a user-defined constructor or destructor, S is not trivial. In that case, thread_local in c++ will generate code to initialize and destroy the thread_local, but that will not happen if the variable is first accessed by a C TU
So my idea of an attribute to apply to the type is not helping (we don't care about incomplete types because that's ill-formed).
Another idea, brought up by Tom, was the idea of some syntax at point of use:
extern "C" thread_local S foo;
But the compiler still needs to create code for initialization and destruction. I guess in that case, the compiler can eagerly run the initialization, and that solves the not-yet-initialized problem C faces.
So Tom's solution is actually workable, and mine was just nonsense :)
But I think there is something else to think about here
void f() {
static thread_local S foo;
c_function(&foo); //#1
}
My understanding is that #1 is the issue here. Do we agree with that?
If that is the case, then I think we might have perfect information here
Indeed, c_function here is an extern "C" function (Are there cases where it isn't?).
A compiler could diagnose a call to c_function with a non-trivial thread_local object before initialization. I think. Has that been considered?
I understand this shifts the burden as a matter of QOI, unless we want to mandate it,
but it avoids burdening both languages and users with extra syntax complexity.
I might miss some important bits of informations so please do not take this as more than an unfiltered stream of consciousness
I think the proposal of no_destroy is generally useful yet orthogonal to C compat concerns.
Thanks,
Corentin