c-common.c (c_common_reswords): Add _Thread_local.
authorJoseph Myers <joseph@codesourcery.com>
Tue, 12 Nov 2013 17:38:47 +0000 (17:38 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Tue, 12 Nov 2013 17:38:47 +0000 (17:38 +0000)
c-family:
* c-common.c (c_common_reswords): Add _Thread_local.

c:
* c-tree.h (struct c_declspecs): Add thread_gnu_p field.
* c-parser.c (c_parser_declspecs): Mention _Thread_local in
comment.
* c-decl.c (shadow_tag_warned, grokdeclarator): Mention __thread
or _Thread_local as appropriate in diagnostics.
(build_null_declspecs): Initialize ret->thread_gnu_p.
(declspecs_add_scspec): Handle either __thread or _Thread_local
for RID_THREAD.  Diagnose _Thread_local for pre-C11 standards if
pedantic.  Do not disallow _Thread_local extern and _Thread_local
static.

testsuite:
* gcc.dg/c90-thread-local-1.c, gcc.dg/c99-thread-local-1.c,
gcc.dg/c11-thread-local-1.c, gcc.dg/c11-thread-local-2.c: New
tests.
* gcc.dg/tls/diag-2.c, objc.dg/tls/diag-2.m: Update expected
diagnostics.

From-SVN: r204711

13 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/c/c-parser.c
gcc/c/c-tree.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/c11-thread-local-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c11-thread-local-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c90-thread-local-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c99-thread-local-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/tls/diag-2.c
gcc/testsuite/objc.dg/tls/diag-2.m

index 6b2a5ab811b41589e0f1d76e065f762a78e9ccf3..1a38bd4d301bd444c165efebb0820b2c129ed307 100644 (file)
@@ -1,3 +1,7 @@
+2013-11-12  Joseph Myers  <joseph@codesourcery.com>
+
+       * c-common.c (c_common_reswords): Add _Thread_local.
+
 2013-11-09  Joseph Myers  <joseph@codesourcery.com>
 
        * c-common.c (atomic_size_supported_p): New function.
index 93481b9302713c33e93783d7d3519fedab0dbba2..1c317439b0b983edf881ae390944192cef4b5fb4 100644 (file)
@@ -424,6 +424,7 @@ const struct c_common_resword c_common_reswords[] =
   { "_Static_assert",   RID_STATIC_ASSERT, D_CONLY },
   { "_Noreturn",        RID_NORETURN,  D_CONLY },
   { "_Generic",         RID_GENERIC,   D_CONLY },
+  { "_Thread_local",    RID_THREAD,    D_CONLY },
   { "__FUNCTION__",    RID_FUNCTION_NAME, 0 },
   { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
   { "__alignof",       RID_ALIGNOF,    0 },
index e38bcb8cdbd936ccbdb2397600e502519deb5902..1cf5883c84815a98e8b5df3d450a60f0d4c53651 100644 (file)
@@ -1,3 +1,16 @@
+2013-11-12  Joseph Myers  <joseph@codesourcery.com>
+
+       * c-tree.h (struct c_declspecs): Add thread_gnu_p field.
+       * c-parser.c (c_parser_declspecs): Mention _Thread_local in
+       comment.
+       * c-decl.c (shadow_tag_warned, grokdeclarator): Mention __thread
+       or _Thread_local as appropriate in diagnostics.
+       (build_null_declspecs): Initialize ret->thread_gnu_p.
+       (declspecs_add_scspec): Handle either __thread or _Thread_local
+       for RID_THREAD.  Diagnose _Thread_local for pre-C11 standards if
+       pedantic.  Do not disallow _Thread_local extern and _Thread_local
+       static.
+
 2013-11-07  Joseph Myers  <joseph@codesourcery.com>
            Andrew MacLeod  <amacleod@redhat.com>
 
index 9520e4d2d6ef4644a4d61cf8e913b93b11cc5333..6fe418e9e4cf225853ac64b6c5ca91808c369028 100644 (file)
@@ -3805,7 +3805,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
 
   if (!warned && !in_system_header && declspecs->thread_p)
     {
-      warning (0, "useless %<__thread%> in empty declaration");
+      warning (0, "useless %qs in empty declaration",
+              declspecs->thread_gnu_p ? "__thread" : "_Thread_local");
       warned = 2;
     }
 
@@ -5164,7 +5165,8 @@ grokdeclarator (const struct c_declarator *declarator,
       if (storage_class == csc_typedef)
        error_at (loc, "function definition declared %<typedef%>");
       if (threadp)
-       error_at (loc, "function definition declared %<__thread%>");
+       error_at (loc, "function definition declared %qs",
+                 declspecs->thread_gnu_p ? "__thread" : "_Thread_local");
       threadp = false;
       if (storage_class == csc_auto
          || storage_class == csc_register
@@ -5233,8 +5235,8 @@ grokdeclarator (const struct c_declarator *declarator,
       else if (threadp && storage_class == csc_none)
        {
          error_at (loc, "function-scope %qE implicitly auto and declared "
-                   "%<__thread%>",
-                   name);
+                   "%qs", name,
+                   declspecs->thread_gnu_p ? "__thread" : "_Thread_local");
          threadp = false;
        }
     }
@@ -8980,6 +8982,7 @@ build_null_declspecs (void)
   ret->inline_p = false;
   ret->noreturn_p = false;
   ret->thread_p = false;
+  ret->thread_gnu_p = false;
   ret->const_p = false;
   ret->volatile_p = false;
   ret->atomic_p = false;
@@ -9773,14 +9776,29 @@ declspecs_add_scspec (source_location loc,
     case RID_THREAD:
       dupe = specs->thread_p;
       if (specs->storage_class == csc_auto)
-       error ("%<__thread%> used with %<auto%>");
+       error ("%qE used with %<auto%>", scspec);
       else if (specs->storage_class == csc_register)
-       error ("%<__thread%> used with %<register%>");
+       error ("%qE used with %<register%>", scspec);
       else if (specs->storage_class == csc_typedef)
-       error ("%<__thread%> used with %<typedef%>");
+       error ("%qE used with %<typedef%>", scspec);
       else
        {
          specs->thread_p = true;
+         specs->thread_gnu_p = (strcmp (IDENTIFIER_POINTER (scspec),
+                                        "__thread") == 0);
+         /* A diagnostic is not required for the use of this
+            identifier in the implementation namespace; only diagnose
+            it for the C11 spelling because of existing code using
+            the other spelling.  */
+         if (!flag_isoc11 && !specs->thread_gnu_p)
+           {
+             if (flag_isoc99)
+               pedwarn (loc, OPT_Wpedantic,
+                        "ISO C99 does not support %qE", scspec);
+             else
+               pedwarn (loc, OPT_Wpedantic,
+                        "ISO C90 does not support %qE", scspec);
+           }
          specs->locations[cdw_thread] = loc;
        }
       break;
@@ -9790,7 +9808,7 @@ declspecs_add_scspec (source_location loc,
     case RID_EXTERN:
       n = csc_extern;
       /* Diagnose "__thread extern".  */
-      if (specs->thread_p)
+      if (specs->thread_p && specs->thread_gnu_p)
        error ("%<__thread%> before %<extern%>");
       break;
     case RID_REGISTER:
@@ -9799,7 +9817,7 @@ declspecs_add_scspec (source_location loc,
     case RID_STATIC:
       n = csc_static;
       /* Diagnose "__thread static".  */
-      if (specs->thread_p)
+      if (specs->thread_p && specs->thread_gnu_p)
        error ("%<__thread%> before %<static%>");
       break;
     case RID_TYPEDEF:
@@ -9811,7 +9829,12 @@ declspecs_add_scspec (source_location loc,
   if (n != csc_none && n == specs->storage_class)
     dupe = true;
   if (dupe)
-    error ("duplicate %qE", scspec);
+    {
+      if (i == RID_THREAD)
+       error ("duplicate %<_Thread_local%> or %<__thread%>");
+      else
+       error ("duplicate %qE", scspec);
+    }
   if (n != csc_none)
     {
       if (specs->storage_class != csc_none && n != specs->storage_class)
@@ -9824,7 +9847,9 @@ declspecs_add_scspec (source_location loc,
          specs->locations[cdw_storage_class] = loc;
          if (n != csc_extern && n != csc_static && specs->thread_p)
            {
-             error ("%<__thread%> used with %qE", scspec);
+             error ("%qs used with %qE",
+                    specs->thread_gnu_p ? "__thread" : "_Thread_local",
+                    scspec);
              specs->thread_p = false;
            }
        }
index 09cce1c092430ffdb244ba287594851caf0b69e6..5b4665a2a8dd99672c6765e61d60747517a0490e 100644 (file)
@@ -1969,6 +1969,9 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser)
      static
      auto
      register
+     _Thread_local
+
+   (_Thread_local is new in C11.)
 
    C99 6.7.4:
    function-specifier:
index 8dffa9c16745f031936363783ba9d70bc23291b1..502fdca4d7ed644b2e18aadb801522eb38847714 100644 (file)
@@ -320,8 +320,10 @@ struct c_declspecs {
   BOOL_BITFIELD inline_p : 1;
   /* Whether "_Noreturn" was speciied.  */
   BOOL_BITFIELD noreturn_p : 1;
-  /* Whether "__thread" was specified.  */
+  /* Whether "__thread" or "_Thread_local" was specified.  */
   BOOL_BITFIELD thread_p : 1;
+  /* Whether "__thread" rather than "_Thread_local" was specified.  */
+  BOOL_BITFIELD thread_gnu_p : 1;
   /* Whether "const" was specified.  */
   BOOL_BITFIELD const_p : 1;
   /* Whether "volatile" was specified.  */
index 290af4e116d622b5b7d50b8db8519fa95697f0aa..d3be7aa7c69555dc931e4e54a87bcc5ed44addea 100644 (file)
@@ -1,3 +1,11 @@
+2013-11-12  Joseph Myers  <joseph@codesourcery.com>
+
+       * gcc.dg/c90-thread-local-1.c, gcc.dg/c99-thread-local-1.c,
+       gcc.dg/c11-thread-local-1.c, gcc.dg/c11-thread-local-2.c: New
+       tests.
+       * gcc.dg/tls/diag-2.c, objc.dg/tls/diag-2.m: Update expected
+       diagnostics.
+
 2013-11-12  Tristan Gingold  <gingold@adacore.com>
 
        * gnat.dg/aggr21.adb: New test.
diff --git a/gcc/testsuite/gcc.dg/c11-thread-local-1.c b/gcc/testsuite/gcc.dg/c11-thread-local-1.c
new file mode 100644 (file)
index 0000000..b21209a
--- /dev/null
@@ -0,0 +1,28 @@
+/* Test for _Thread_local in C11.  Test of valid code.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+_Thread_local int a;
+static _Thread_local long b;
+extern _Thread_local int c, a;
+_Thread_local static int d;
+long _Thread_local extern b;
+_Thread_local int extern a;
+_Thread_local struct s; /* { dg-warning "useless" } */
+_Thread_local int a = 1;
+extern _Thread_local int c = 2; /* { dg-warning "initialized and" } */
+void
+f (void)
+{
+  static _Thread_local int x;
+  extern _Thread_local long b;
+  _Thread_local extern int a;
+}
+
+inline void
+fi (void)
+{
+  static _Thread_local const int v;
+  (void) a;
+  static _Thread_local int (*const p)[a];
+}
diff --git a/gcc/testsuite/gcc.dg/c11-thread-local-2.c b/gcc/testsuite/gcc.dg/c11-thread-local-2.c
new file mode 100644 (file)
index 0000000..3387226
--- /dev/null
@@ -0,0 +1,46 @@
+/* Test for _Thread_local in C11.  Test of invalid code.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+_Thread_local void f (void); /* { dg-error "storage class" } */
+_Thread_local void g (void) {} /* { dg-error "_Thread_local" } */
+typedef _Thread_local int t1; /* { dg-error "_Thread_local" } */
+_Thread_local typedef int t2; /* { dg-error "_Thread_local" } */
+
+void
+h (void)
+{
+  _Thread_local auto int a; /* { dg-error "_Thread_local" } */
+  _Thread_local register int b; /* { dg-error "_Thread_local" } */
+  auto _Thread_local int c; /* { dg-error "_Thread_local" } */
+  register _Thread_local int d; /* { dg-error "_Thread_local" } */
+  _Thread_local int e; /* { dg-error "_Thread_local" } */
+}
+
+_Thread_local int v; /* { dg-message "previous" } */
+extern int v; /* { dg-error "thread" } */
+int w; /* { dg-message "previous" } */
+extern _Thread_local int w; /* { dg-error "thread" } */
+
+_Thread_local int x; /* { dg-message "previous" } */
+int y; /* { dg-message "previous" } */
+
+int vv;
+
+void
+i (void)
+{
+  extern int x; /* { dg-error "thread" } */
+  extern _Thread_local int y; /* { dg-error "thread" } */
+  static _Thread_local int a[vv]; /* { dg-error "storage size" } */
+  static _Thread_local int vi = vv; /* { dg-error "not constant" } */
+}
+
+static _Thread_local int sv;
+
+inline void
+j (void)
+{
+  static _Thread_local int vj; /* { dg-error "static but declared" } */
+  (void) sv; /* { dg-error "static but used in inline" } */
+}
diff --git a/gcc/testsuite/gcc.dg/c90-thread-local-1.c b/gcc/testsuite/gcc.dg/c90-thread-local-1.c
new file mode 100644 (file)
index 0000000..92bf57a
--- /dev/null
@@ -0,0 +1,5 @@
+/* Test for _Thread_local: not in C90.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c90 -pedantic-errors" } */
+
+static _Thread_local int x; /* { dg-error "_Thread_local" } */
diff --git a/gcc/testsuite/gcc.dg/c99-thread-local-1.c b/gcc/testsuite/gcc.dg/c99-thread-local-1.c
new file mode 100644 (file)
index 0000000..ff53125
--- /dev/null
@@ -0,0 +1,5 @@
+/* Test for _Thread_local: not in C99.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c99 -pedantic-errors" } */
+
+static _Thread_local int x; /* { dg-error "_Thread_local" } */
index 8276cb3be4902553c2da9b5d64685480bcf9e51a..854824385a50f6ac677552fe2fee21fb87224b49 100644 (file)
@@ -3,7 +3,7 @@
 
 __thread extern int g1;                /* { dg-error "'__thread' before 'extern'" } */
 __thread static int g2;                /* { dg-error "'__thread' before 'static'" } */
-__thread __thread int g3;      /* { dg-error "duplicate '__thread'" } */
+__thread __thread int g3;      /* { dg-error "duplicate" } */
 typedef __thread int g4;       /* { dg-error "'__thread' used with 'typedef'" } */
 
 void foo()
index 4f22281eb9c9d87d10908aafe36caba88386ba60..58cca01494bbe014efcfa6549e7b759218a4fa87 100644 (file)
@@ -3,7 +3,7 @@
 
 __thread extern int g1;                /* { dg-error "'__thread' before 'extern'" } */
 __thread static int g2;                /* { dg-error "'__thread' before 'static'" } */
-__thread __thread int g3;      /* { dg-error "duplicate '__thread'" } */
+__thread __thread int g3;      /* { dg-error "duplicate" } */
 typedef __thread int g4;       /* { dg-error " '__thread' used with 'typedef'" } */
 
 void foo()