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);
/* 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)))
--- /dev/null
+/* Test that thread-local declarations are not considered tentative definitions
+ in C2x. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+thread_local int a; /* { dg-message "previous" } */
+thread_local int a; /* { dg-error "redefinition" } */
+
+static thread_local int b; /* { dg-message "previous" } */
+static thread_local int b; /* { dg-error "redefinition" } */
+
+thread_local int c; /* { dg-message "previous" } */
+thread_local int c = 1; /* { dg-error "redefinition" } */
+
+static thread_local int d; /* { dg-message "previous" } */
+static thread_local int d = 1; /* { dg-error "redefinition" } */
+
+thread_local int e = 1; /* { dg-message "previous" } */
+thread_local int e; /* { dg-error "redefinition" } */
+
+static thread_local int f = 1; /* { dg-message "previous" } */
+static thread_local int f; /* { dg-error "redefinition" } */
+
+/* Not being a tentative definition means that incomplete arrays are an error
+ rather than defaulting to size 1. */
+thread_local int g[]; /* { dg-error "storage size" } */
+static thread_local int h[]; /* { dg-error "array size missing" } */
+extern thread_local int i[];
+
+thread_local int j[] = { 0 };
+static thread_local int k[] = { 0 };
+
+thread_local int l;
+extern thread_local int l;
+
+extern thread_local int m;
+thread_local int m;
+
+static thread_local int n;
+extern thread_local int n;