* decl.c (check_tag_decl): Handle RID_THREAD.
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 22 May 2002 23:42:57 +0000 (23:42 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Wed, 22 May 2002 23:42:57 +0000 (23:42 +0000)
        (obscure_complex_init): Reject run-time init of tls.
        (grokvardecl, grokdeclarator): Handle RID_THREAD.
        * lex.c (reswords): Add __thread.
        (rid_to_yy): Map RID_THREAD to SCSPEC.

        * g++.dg/dg.exp: Prune the tls subdirectory.
        * g++.dg/tls/tls.exp, g++.dg/tls/trivial.C: New.
        * g++.dg/tls/diag-1.C, g++.dg/tls/diag-2.C: New.
        * g++.dg/tls/init-1.C: New.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@53754 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/lex.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/dg.exp
gcc/testsuite/g++.dg/tls/diag-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/diag-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/init-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/init-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/tls.exp [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/trivial.C [new file with mode: 0644]

index 9a2e55e..69008fd 100644 (file)
@@ -1,3 +1,11 @@
+2002-05-22  Richard Henderson  <rth@redhat.com>
+
+       * decl.c (check_tag_decl): Handle RID_THREAD.
+       (obscure_complex_init): Reject run-time init of tls.
+       (grokvardecl, grokdeclarator): Handle RID_THREAD.
+       * lex.c (reswords): Add __thread.
+       (rid_to_yy): Map RID_THREAD to SCSPEC.
+
 2002-05-22  Neil Booth  <neil@daikokuya.demon.co.uk>
 
        * cp-lang.c (LANG_HOOKS_POST_OPTIONS): Use c_common_post_options.
index 6c5b979..dbdc6f2 100644 (file)
@@ -7106,7 +7106,8 @@ check_tag_decl (declspecs)
               || value == ridpointers[(int) RID_VIRTUAL]
               || value == ridpointers[(int) RID_CONST]
               || value == ridpointers[(int) RID_VOLATILE]
-              || value == ridpointers[(int) RID_EXPLICIT])
+              || value == ridpointers[(int) RID_EXPLICIT]
+              || value == ridpointers[(int) RID_THREAD])
        ob_modifier = value;
     }
 
@@ -7580,6 +7581,12 @@ static tree
 obscure_complex_init (decl, init)
      tree decl, init;
 {
+  if (DECL_THREAD_LOCAL (decl))
+    {
+      error ("run-time initialization of thread-local storage");
+      return NULL_TREE;
+    }
+
   if (! flag_no_inline && TREE_STATIC (decl))
     {
       if (extract_init (decl, init))
@@ -9274,6 +9281,16 @@ grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace)
       TREE_PUBLIC (decl) = DECL_EXTERNAL (decl);
     }
 
+  if (RIDBIT_SETP (RID_THREAD, specbits))
+    {
+      if (targetm.have_tls)
+       DECL_THREAD_LOCAL (decl) = 1;
+      else
+       /* A mere warning is sure to result in improper semantics
+          at runtime.  Don't bother to allow this to compile.  */
+       error ("thread-local storage not supported for this target");
+    }
+
   if (TREE_PUBLIC (decl))
     {
       /* [basic.link]: A name with no linkage (notably, the name of a class
@@ -10176,10 +10193,22 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
                    }
                  else if (RIDBIT_SETP (i, specbits))
                    pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));
+
+                 /* Diagnose "__thread extern".  Recall that this list
+                    is in the reverse order seen in the text.  */
+                 if (i == (int)RID_THREAD)
+                   {
+                     if (RIDBIT_SETP (RID_EXTERN, specbits))
+                       error ("`__thread' before `extern'");
+                     if (RIDBIT_SETP (RID_STATIC, specbits))
+                       error ("`__thread' before `static'");
+                   }
+
                  if (i == (int)RID_EXTERN
                      && TREE_PURPOSE (spec) == error_mark_node)
                    /* This extern was part of a language linkage.  */
                    extern_langp = 1;
+
                  RIDBIT_SET (i, specbits);
                  goto found;
                }
@@ -10476,6 +10505,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
     {
       if (RIDBIT_SETP (RID_STATIC, specbits)) nclasses++;
       if (RIDBIT_SETP (RID_EXTERN, specbits) && !extern_langp) nclasses++;
+      if (RIDBIT_SETP (RID_THREAD, specbits)) nclasses++;
       if (decl_context == PARM && nclasses > 0)
        error ("storage class specifiers invalid in parameter declarations");
       if (RIDBIT_SETP (RID_TYPEDEF, specbits))
@@ -10507,6 +10537,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
   /* Warn about storage classes that are invalid for certain
      kinds of declarations (parameters, typenames, etc.).  */
 
+  /* "static __thread" and "extern __thread" are allowed.  */
+  if (nclasses == 2
+      && RIDBIT_SETP (RID_THREAD, specbits)
+      && (RIDBIT_SETP (RID_EXTERN, specbits)
+         || RIDBIT_SETP (RID_STATIC, specbits)))
+    nclasses = 1;
+    
   if (nclasses > 1)
     error ("multiple storage classes in declaration of `%s'", name);
   else if (decl_context != NORMAL && nclasses > 0)
@@ -10562,6 +10599,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
          RIDBIT_RESET (RID_REGISTER, specbits);
          RIDBIT_RESET (RID_AUTO, specbits);
          RIDBIT_RESET (RID_EXTERN, specbits);
+         RIDBIT_RESET (RID_THREAD, specbits);
        }
     }
   else if (RIDBIT_SETP (RID_EXTERN, specbits) && initialized && !funcdef_flag)
@@ -10584,6 +10622,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
       if (RIDBIT_SETP (RID_AUTO, specbits))
        error ("top-level declaration of `%s' specifies `auto'", name);
     }
+  else if (RIDBIT_SETP (RID_THREAD, specbits)
+          && !RIDBIT_SETP (RID_EXTERN, specbits)
+          && !RIDBIT_SETP (RID_STATIC, specbits))
+    {
+      error ("function-scope `%s' implicitly auto and declared `__thread'",
+            name);
+      RIDBIT_RESET (RID_THREAD, specbits);
+    }
 
   if (nclasses > 0 && friendp)
     error ("storage class specifiers invalid in friend function declarations");
@@ -11784,6 +11830,8 @@ friend declaration requires class-key, i.e. `friend %#T'",
          error ("storage class `auto' invalid for function `%s'", name);
        else if (RIDBIT_SETP (RID_REGISTER, specbits))
          error ("storage class `register' invalid for function `%s'", name);
+       else if (RIDBIT_SETP (RID_THREAD, specbits))
+         error ("storage class `__thread' invalid for function `%s'", name);
 
        /* Function declaration not at top level.
           Storage classes other than `extern' are not allowed
index 91931d4..a2b0dd3 100644 (file)
@@ -362,6 +362,7 @@ static const struct resword reswords[] =
   { "__restrict__",    RID_RESTRICT,   0 },
   { "__signed",                RID_SIGNED,     0 },
   { "__signed__",      RID_SIGNED,     0 },
+  { "__thread",                RID_THREAD,     0 },
   { "__typeof",                RID_TYPEOF,     0 },
   { "__typeof__",      RID_TYPEOF,     0 },
   { "__volatile",      RID_VOLATILE,   0 },
@@ -467,7 +468,7 @@ const short rid_to_yy[RID_MAX] =
   /* RID_BOUNDED */    0,
   /* RID_UNBOUNDED */  0,
   /* RID_COMPLEX */    TYPESPEC,
-  /* RID_THREAD */     0,
+  /* RID_THREAD */     SCSPEC,
 
   /* C++ */
   /* RID_FRIEND */     SCSPEC,
index eb45471..9807295 100644 (file)
@@ -1,3 +1,10 @@
+2002-05-22  Richard Henderson  <rth@redhat.com>
+
+       * g++.dg/dg.exp: Prune the tls subdirectory.
+       * g++.dg/tls/tls.exp, g++.dg/tls/trivial.C: New.
+       * g++.dg/tls/diag-1.C, g++.dg/tls/diag-2.C: New.
+       * g++.dg/tls/init-1.C: New.
+
 2002-05-22  Jakub Jelinek  <jakub@redhat.com>
 
        * gcc.dg/20020517-1.c: New test.
@@ -168,11 +175,11 @@ Mon May 20 10:51:35 2002  J"orn Rennecke <joern.rennecke@superh.com>
 
 2002-05-02  Aldy Hernandez  <aldyh@redhat.com>
 
-        * gcc.dg/altivec-8.c: New.
+       * gcc.dg/altivec-8.c: New.
 
 2002-05-01  Aldy Hernandez  <aldyh@redhat.com>
 
-        * gcc.dg/altivec-7.c: New.
+       * gcc.dg/altivec-7.c: New.
 
 2002-04-29  Jakub Jelinek  <jakub@redhat.com>
 
@@ -319,8 +326,8 @@ Wed Apr 24 21:38:36 2002  J"orn Rennecke <joern.rennecke@superh.com>
 
 2002-04-18  Richard Henderson  <rth@redhat.com>
 
-        * gcc.dg/20000906-1.c: Enable for all targets.
-        * gcc.c-torture/compile/iftrap-2.c: New.
+       * gcc.dg/20000906-1.c: Enable for all targets.
+       * gcc.c-torture/compile/iftrap-2.c: New.
 
 2002-04-18  Jakub Jelinek  <jakub@redhat.com>
 
@@ -329,9 +336,9 @@ Wed Apr 24 21:38:36 2002  J"orn Rennecke <joern.rennecke@superh.com>
 
 2002-04-18  Richard Henderson  <rth@redhat.com>
 
-        * gcc.c-torture/compile/iftrap-1.c: New.
-        * gcc.dg/iftrap-1.c: Adjust for ia64.
-        * gcc.dg/iftrap-2.c: New.
+       * gcc.c-torture/compile/iftrap-1.c: New.
+       * gcc.dg/iftrap-1.c: Adjust for ia64.
+       * gcc.dg/iftrap-2.c: New.
 
 2002-04-18  Jakub Jelinek  <jakub@redhat.com>
 
index b59d302..da499be 100644 (file)
@@ -31,10 +31,11 @@ dg-init
 # Gather a list of all tests, with the exception of those in directories
 # that are handled specially.
 set all [lsort [find $srcdir/$subdir *.C]]
-set tests [prune [prune [prune [prune $all $srcdir/$subdir/special/*] \
-                               $srcdir/$subdir/debug/*] \
-                        $srcdir/$subdir/gcov/*] \
-                 $srcdir/$subdir/bprob/*]
+set tests [prune $tests $srcdir/$subdir/bprob/*]
+set tests [prune $tests $srcdir/$subdir/debug/*]
+set tests [prune $tests $srcdir/$subdir/gcov/*]
+set tests [prune $tests $srcdir/$subdir/special/*]
+set tests [prune $tests $srcdir/$subdir/tls/*]
 
 # Main loop.
 dg-runtest $tests "" $DEFAULT_CXXFLAGS
diff --git a/gcc/testsuite/g++.dg/tls/diag-1.C b/gcc/testsuite/g++.dg/tls/diag-1.C
new file mode 100644 (file)
index 0000000..697d0b1
--- /dev/null
@@ -0,0 +1,30 @@
+/* Valid __thread specifiers.  */
+
+__thread int g1;
+extern __thread int g2;
+static __thread int g3;
+
+void foo()
+{
+  extern __thread int l1;
+  static __thread int l2;
+}
+
+struct A {
+  static __thread int i;
+};
+
+__thread int A::i = 42;
+
+template <typename T> struct B {
+  static __thread T t;
+};
+
+template <typename T>
+__thread T B<T>::t = 42;
+
+void bar ()
+{
+  int j = B<int>::t;
+  int k = B<const int>::t;
+}
diff --git a/gcc/testsuite/g++.dg/tls/diag-2.C b/gcc/testsuite/g++.dg/tls/diag-2.C
new file mode 100644 (file)
index 0000000..6365406
--- /dev/null
@@ -0,0 +1,25 @@
+/* Invalid __thread specifiers.  */
+
+__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'" } */
+typedef __thread int g4;       /* { dg-error "multiple storage classes" } */
+
+void foo()
+{
+  __thread int l1;             /* { dg-error "implicitly auto and declared `__thread'" } */
+  auto __thread int l2;                /* { dg-error "multiple storage classes" } */
+  __thread extern int l3;      /* { dg-error "`__thread' before `extern'" } */
+  register __thread int l4;    /* { dg-error "multiple storage classes" } */
+}
+
+__thread void f1 ();           /* { dg-error "invalid for function" } */
+extern __thread void f2 ();    /* { dg-error "invalid for function" } */
+static __thread void f3 ();    /* { dg-error "invalid for function" } */
+__thread void f4 () { }                /* { dg-error "invalid for function" } */
+
+void bar(__thread int p1);     /* { dg-error "(invalid in parameter)|(specified for parameter)" } */
+
+struct A {
+  __thread int i;              /* { dg-error "specified for field" } */
+};
diff --git a/gcc/testsuite/g++.dg/tls/init-1.C b/gcc/testsuite/g++.dg/tls/init-1.C
new file mode 100644 (file)
index 0000000..74f7641
--- /dev/null
@@ -0,0 +1,13 @@
+/* Valid initializations.  */
+
+__thread int i = 42;
+
+static int j;
+__thread int *p = &j;
+
+/* Note that this is valid in C++ (unlike C) as a run-time initialization.  */
+int *q = &i;
+
+/* Valid because "const int k" is an integral constant expression in C++.  */
+__thread const int k = 42;
+__thread const int l = k;
diff --git a/gcc/testsuite/g++.dg/tls/init-2.C b/gcc/testsuite/g++.dg/tls/init-2.C
new file mode 100644 (file)
index 0000000..49df501
--- /dev/null
@@ -0,0 +1,13 @@
+/* Invalid initializations.  */
+
+extern __thread int i;
+__thread int *p = &i;  /* { dg-error "run-time initialization" } */
+
+extern int f();
+__thread int j = f();  /* { dg-error "run-time initialization" } */
+
+struct S
+{
+  S();
+};
+__thread S s;          /* { dg-error "run-time initialization" } */
diff --git a/gcc/testsuite/g++.dg/tls/tls.exp b/gcc/testsuite/g++.dg/tls/tls.exp
new file mode 100644 (file)
index 0000000..a00dad7
--- /dev/null
@@ -0,0 +1,44 @@
+#   Copyright (C) 2002 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+# 
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib g++-dg.exp
+
+# Test for thread-local data supported by the platform.  If it
+# isn't, everything will fail with the "not supported" message.
+
+set comp_output [g++_target_compile \
+               "$srcdir/$subdir/trivial.C" "trivial.S" assembly ""]
+if { [string match "*not supported*" $comp_output] } {
+  return 0
+}
+
+# If a testcase doesn't have special options, use these.
+global DEFAULT_CXXFLAGS
+if ![info exists DEFAULT_CXXFLAGS] then {
+    set DEFAULT_CXXFLAGS " -ansi -pedantic-errors -Wno-long-long"
+}
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" $DEFAULT_CXXFLAGS
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/g++.dg/tls/trivial.C b/gcc/testsuite/g++.dg/tls/trivial.C
new file mode 100644 (file)
index 0000000..1fd7063
--- /dev/null
@@ -0,0 +1 @@
+__thread int i;