Andrew Pinski wrote: > I would have hoped people actually read: > http://gcc.gnu.org/onlinedocs/gcc/C99-Thread_002dLocal-Edits.html > > Which actually describes the edits to the C99 standard to how > __thread is supposed to behave.
Thanks for the reference. Per that proposal, __thread is a storage-class specifier, which makes sense. I may have confused the issue by offering up an example using 'const' -- the point of the example was really just to show that the implementor of the __thread check wasn't lazy, but was following suit on the qualifier check. Given that __thread is a proposed extension, there isn't much precedent to lean on, because generally 'extern' can only refer to block scope identifiers and those objects are inherently global, and from the point of view of the "C" program referring to the objects, the actual method used to link, load, and access those objects is implementation defined. (Btw, personally, I'd prefer that a propoasl to extend the "C" language use something other than a keyword beginning with __ as a way of doing that. For example, a compound keyword such as "thread local" would read better and is unlikely to clobber many existing programs. If the idea of a compound keyword is too offensive, then thread_local seems a lot better than __thread to me.) Applying the proposed standard to the following: Dave Korn wrote: > Reasons like this are why we have 6.2.7.2 in the C language spec, aren't > they? > > "All declarations that refer to the same object or function shall have > compatible type; otherwise, the behavior is undefined." The answer is probably, no. Because the presence or absence of storage specifiers shouldn't affect type compatibilty. In reply to my question: > > What are the technical reasons for the front-end enforcing this > restriction, > > when apparently some linkers will handle the TLS linkage fine? > If in fact > > it is required that __thread be added to the extern, is the > compiler simply > > accommodating a limitation/bug in the linker? Seongbae Park wrote: > Because the compiler has to generate different code > for accesses to __thread vs non __thread variable In my view, this is implementation-defined, and generally can vary depending upon the underlying linker and OS technology. Further, there is at least one known platform (IA64) which seems to not impose this restriction. A few implementation techniques come to mind, where the programmer would not need to explicitly tag 'extern's with __thread: 1. The linker can fix up external references to __thread variables by inserting jumps to a "thunk" that executes the appropriate instuctions and then jumps back to the point following the original instruction. The IA64 linker might already be doing that. 2. The entire program might be compiled in some sort of PIC mode, where all external references go through some sort of indirect table, or some small subroutine is called to load the proper address, and there is no distinction between regular extern references and extern __thread references. 3. The linker coallesces __thread objects into a special linkage segment, and the OS allocates a new instance of this segment when it instantiates a thread. From the thread's point of view, access to this per-thread segment is just a regular memory reference. Thread creation may be slower, but access to TLS data is faster. Thus, I don't think gcc should be checking for the presence of the __thread specifier applied to an extern when the referenced object is also declared as having __thread persistance, and both declarations happen to be visible in a given compilation unit. If this check must remain, I think it should be down-graded to a warning (with a flag to turn off the warning), and the check should be target-tuple specific, with possible further target-dependent checks (such as special PIC modes, etc.). This part of the proposed spec.: "The declaration of an identifier for a variable that has block scope that specifies __thread shall also specify either extern or static." seems to indicate that following declaration (at block scope) is erroneous: int __thread x; because it has neither "static" nor "extern" preceding it. Interestingly, when declared at an inner scope, the declaration above appears to be allowed, because __thread is a storage specifier. Perhaps the "C" standard says somewhere that a bare block scope declaration implies "extern", but the language in the spec. seems to call out precisely the presence of either "static" or "extern" ahead of __thread in block scope declarations. Thus, it seems that if gcc is going to move towards the proposed standard, it should also deprecate block scope declarations that aren't preceeded with either "extern" or "static"? (and perhaps it should do this in preference to matching up bare declartions with extern declarations). If extern is required for block scoped objects then it seems to imply that those objects can't be statically initialized, where those declared with "static" may be. Regarding Mike's conjecture that a bare extern should be able to match up with a more fully qualified declaration, it would be interesting to hear what the language lawyers think, but that is a separate question from making the check for matching uses of __thread.