aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2023-05-19 00:42:07 +0000
committerJoseph Myers <joseph@codesourcery.com>2023-05-19 00:42:07 +0000
commitc3db10967411be9c17f0ef01f13e82a947b7e12f (patch)
tree2e1f280b550a5d579ab71933545b01450f527050 /gcc/c
parentb27760769ca03ff523caf0ec0b17296d3a2d8dba (diff)
downloadgcc-c3db10967411be9c17f0ef01f13e82a947b7e12f.zip
gcc-c3db10967411be9c17f0ef01f13e82a947b7e12f.tar.gz
gcc-c3db10967411be9c17f0ef01f13e82a947b7e12f.tar.bz2
c: Do not allow thread-local tentative definitions for C2x
C2x makes it clear that thread-local declarations can never be tentative definitions (the legacy feature of C where you can e.g. do "int i;" more than once at file scope, possibly with one of the declarations initialized, and it counts as exactly one definition), but are always definitions in the absence of "extern". The wording about external definitions was unclear in the thread-local case in C11 / C17 (both about what counts as a tentative definition, and what is a "definition" at all), not having been updated to cover the addition of thread-local storage. Implement this C2x requirement. Arguably this is a defect fix that would be appropriate to apply for all standard versions, but for now the change is conditional on flag_isoc2x (however, it doesn't handle _Thread_local / thread_local any different from GNU __thread). Making the change unconditional results in various TLS tests failing to compile (gcc.dg/c11-thread-local-1.c gcc.dg/tls/thr-init-1.c gcc.dg/tls/thr-init-2.c gcc.dg/torture/tls/thr-init-2.c objc.dg/torture/tls/thr-init.m), though it's not clear if those tests reflect any real code similarly trying to make use of thread-local tentative definitions. Bootstrapped with no regressions for x86_64-pc-linux-gnu. gcc/c/ * c-decl.cc (diagnose_mismatched_decls): Do not handle thread-local declarations as tentative definitions for C2x. (finish_decl): Do not allow thread-local definition with incomplete type for C2x. gcc/testsuite/ * gcc.dg/c2x-thread-local-2.c: New test.
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/c-decl.cc20
1 files changed, 17 insertions, 3 deletions
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 945e45b..b5b491c 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2442,8 +2442,20 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
return false;
}
- /* Multiple initialized definitions are not allowed (6.9p3,5). */
- if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl))
+ /* Multiple initialized definitions are not allowed (6.9p3,5).
+ For this purpose, C2x makes it clear that thread-local
+ declarations without extern are definitions, not tentative
+ definitions, whether or not they have initializers. The
+ wording before C2x was unclear; literally it would have made
+ uninitialized thread-local declarations into tentative
+ definitions only if they also used static, but without saying
+ explicitly whether or not other cases count as
+ definitions at all. */
+ if ((DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl))
+ || (flag_isoc2x
+ && DECL_THREAD_LOCAL_P (newdecl)
+ && !DECL_EXTERNAL (newdecl)
+ && !DECL_EXTERNAL (olddecl)))
{
auto_diagnostic_group d;
error ("redefinition of %q+D", newdecl);
@@ -5714,10 +5726,12 @@ finish_decl (tree decl, location_t init_loc, tree init,
/* A static variable with an incomplete type
is an error if it is initialized.
Also if it is not file scope.
+ Also if it is thread-local (in C2x).
Otherwise, let it through, but if it is not `extern'
then it may cause an error message later. */
? (DECL_INITIAL (decl) != NULL_TREE
- || !DECL_FILE_SCOPE_P (decl))
+ || !DECL_FILE_SCOPE_P (decl)
+ || (flag_isoc2x && DECL_THREAD_LOCAL_P (decl)))
/* An automatic variable with an incomplete type
is an error. */
: !DECL_EXTERNAL (decl)))