]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Partial implementation of C++11 thread_local.
authorJason Merrill <jason@redhat.com>
Mon, 8 Oct 2012 14:45:12 +0000 (10:45 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 8 Oct 2012 14:45:12 +0000 (10:45 -0400)
c-family/
* c-common.c (c_common_reswords): Add thread_local.
cp/
* decl.c (cp_finish_decl): Remove errors about non-trivial
initialization and destruction of TLS variables.
(register_dtor_fn): Add sorry about TLS variables.
(expand_static_init): Add sorry about non-local TLS variables,
or error with __thread.
Don't emit thread-safety guards for local TLS variables.
(grokdeclarator): thread_local in a function implies static.
* decl.h: Adjust prototype.
* decl2.c (get_guard): Copy DECL_TLS_MODEL.
* parser.c (cp_parser_set_storage_class, cp_parser_set_decl_spec_type)
(set_and_check_decl_spec_loc): Take the token rather than the location.
Distinguish between __thread and thread_local.
(cp_parser_set_storage_class): Don't complain about thread_local before
extern/static.
(token_is__thread): New.
* call.c (make_temporary_var_for_ref_to_temp): Handle TLS.
* cp-tree.h (DECL_GNU_TLS_P): New.
(cp_decl_specifier_seq): Add gnu_thread_keyword_p.

From-SVN: r192209

14 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl.h
gcc/cp/decl2.c
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/tls/init-2.C
gcc/testsuite/g++.dg/tls/thread_local1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/tls/thread_local7.C [new file with mode: 0644]

index b49388df86df1f6edc8b74f5035f7d03deb6509f..36bab2ee23eabcdee28c8e5420191d4b8ec7ce8c 100644 (file)
@@ -1,3 +1,7 @@
+2012-10-08  Jason Merrill  <jason@redhat.com>
+
+       * c-common.c (c_common_reswords): Add thread_local.
+
 2012-10-08  Dodji Seketeli  <dodji@redhat.com>
 
        PR c++/53528 C++11 attribute support
index e24278951dabc262d0bdef96871d54ef21e848dd..bb18c39cd6ba1ba8c62ba14f2429525939b0f244 100644 (file)
@@ -543,6 +543,7 @@ const struct c_common_resword c_common_reswords[] =
   { "switch",          RID_SWITCH,     0 },
   { "template",                RID_TEMPLATE,   D_CXXONLY | D_CXXWARN },
   { "this",            RID_THIS,       D_CXXONLY | D_CXXWARN },
+  { "thread_local",    RID_THREAD,     D_CXXONLY | D_CXX0X | D_CXXWARN },
   { "throw",           RID_THROW,      D_CXX_OBJC | D_CXXWARN },
   { "true",            RID_TRUE,       D_CXXONLY | D_CXXWARN },
   { "try",             RID_TRY,        D_CXX_OBJC | D_CXXWARN },
index 660a2199c8fb3495b60979a4c42e9a1b6b3754b7..871dbaa85300d2d173f1ba04edd636ff5d0187fa 100644 (file)
@@ -1,3 +1,25 @@
+2012-10-08  Jason Merrill  <jason@redhat.com>
+
+       Partial implementation of C++11 thread_local.
+       * decl.c (cp_finish_decl): Remove errors about non-trivial
+       initialization and destruction of TLS variables.
+       (register_dtor_fn): Add sorry about TLS variables.
+       (expand_static_init): Add sorry about non-local TLS variables,
+       or error with __thread.
+       Don't emit thread-safety guards for local TLS variables.
+       (grokdeclarator): thread_local in a function implies static.
+       * decl.h: Adjust prototype.
+       * decl2.c (get_guard): Copy DECL_TLS_MODEL.
+       * parser.c (cp_parser_set_storage_class, cp_parser_set_decl_spec_type)
+       (set_and_check_decl_spec_loc): Take the token rather than the location.
+       Distinguish between __thread and thread_local.
+       (cp_parser_set_storage_class): Don't complain about thread_local before
+       extern/static.
+       (token_is__thread): New.
+       * call.c (make_temporary_var_for_ref_to_temp): Handle TLS.
+       * cp-tree.h (DECL_GNU_TLS_P): New.
+       (cp_decl_specifier_seq): Add gnu_thread_keyword_p.
+
 2012-10-08  Dodji Seketeli  <dodji@redhat.com>
 
        PR c++/53528 C++11 attribute support
index f58dc8a52e070824c611bdcc5cf1088f26a189cd..9c8de39e92deaac6816202154b0f2706db719220 100644 (file)
@@ -8719,9 +8719,9 @@ perform_direct_initialization_if_possible (tree type,
 
   The next several functions are involved in this lifetime extension.  */
 
-/* DECL is a VAR_DECL whose type is a REFERENCE_TYPE.  The reference
-   is being bound to a temporary.  Create and return a new VAR_DECL
-   with the indicated TYPE; this variable will store the value to
+/* DECL is a VAR_DECL or FIELD_DECL whose type is a REFERENCE_TYPE.  The
+   reference is being bound to a temporary.  Create and return a new
+   VAR_DECL with the indicated TYPE; this variable will store the value to
    which the reference is bound.  */
 
 tree
@@ -8733,13 +8733,15 @@ make_temporary_var_for_ref_to_temp (tree decl, tree type)
   var = create_temporary_var (type);
 
   /* Register the variable.  */
-  if (TREE_STATIC (decl))
+  if (TREE_CODE (decl) == VAR_DECL
+      && (TREE_STATIC (decl) || DECL_THREAD_LOCAL_P (decl)))
     {
       /* Namespace-scope or local static; give it a mangled name.  */
       /* FIXME share comdat with decl?  */
       tree name;
 
-      TREE_STATIC (var) = 1;
+      TREE_STATIC (var) = TREE_STATIC (decl);
+      DECL_TLS_MODEL (var) = DECL_TLS_MODEL (decl);
       name = mangle_ref_init_variable (decl);
       DECL_NAME (var) = name;
       SET_DECL_ASSEMBLER_NAME (var, name);
index a1d4424018901a9baaaf2c74cce50cde7847aef2..51c8d566e90147a6f533ec91d815aad73dfed4e1 100644 (file)
@@ -56,6 +56,7 @@ c-common.h, not after.
       AGGR_INIT_VIA_CTOR_P (in AGGR_INIT_EXPR)
       PTRMEM_OK_P (in ADDR_EXPR, OFFSET_REF, SCOPE_REF)
       PAREN_STRING_LITERAL (in STRING_CST)
+      DECL_GNU_TLS_P (in VAR_DECL)
       KOENIG_LOOKUP_P (in CALL_EXPR)
       STATEMENT_LIST_NO_SCOPE (in STATEMENT_LIST).
       EXPR_STMT_STMT_EXPR_RESULT (in EXPR_STMT)
@@ -2425,6 +2426,11 @@ struct GTY((variable_size)) lang_decl {
   (DECL_NAME (NODE) \
    && !strcmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__PRETTY_FUNCTION__"))
 
+/* Nonzero if the thread-local variable was declared with __thread
+   as opposed to thread_local.  */
+#define DECL_GNU_TLS_P(NODE) \
+  (TREE_LANG_FLAG_0 (VAR_DECL_CHECK (NODE)))
+
 /* The _TYPE context in which this _DECL appears.  This field holds the
    class where a virtual function instance is actually defined.  */
 #define DECL_CLASS_CONTEXT(NODE) \
@@ -4732,6 +4738,8 @@ typedef struct cp_decl_specifier_seq {
   BOOL_BITFIELD explicit_int128_p : 1;
   /* True iff "char" was explicitly provided.  */
   BOOL_BITFIELD explicit_char_p : 1;
+  /* True iff ds_thread is set for __thread, not thread_local.  */
+  BOOL_BITFIELD gnu_thread_keyword_p : 1;
 } cp_decl_specifier_seq;
 
 /* The various kinds of declarators.  */
index 2848ad5b7be1d1f06574693d42f59688336ab06c..b409c34eee1003d19e31799d6a242636305a73ea 100644 (file)
@@ -6227,13 +6227,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
 
   if (TREE_CODE (decl) == VAR_DECL)
     {
-      /* Only variables with trivial initialization and destruction can
-        have thread-local storage.  */
-      if (DECL_THREAD_LOCAL_P (decl)
-         && (type_has_nontrivial_default_init (TREE_TYPE (decl))
-             || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (decl))))
-       error ("%qD cannot be thread-local because it has non-trivial "
-              "type %qT", decl, TREE_TYPE (decl));
       /* If this is a local variable that will need a mangled name,
         register it now.  We must do this before processing the
         initializer for the variable, since the initialization might
@@ -6279,13 +6272,6 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
            }
          cleanups = make_tree_vector ();
          init = check_initializer (decl, init, flags, &cleanups);
-         /* Thread-local storage cannot be dynamically initialized.  */
-         if (DECL_THREAD_LOCAL_P (decl) && init)
-           {
-             error ("%qD is thread-local and so cannot be dynamically "
-                    "initialized", decl);
-             init = NULL_TREE;
-           }
 
          /* Check that the initializer for a static data member was a
             constant.  Although we check in the parser that the
@@ -6734,6 +6720,12 @@ register_dtor_fn (tree decl)
       end_cleanup_fn ();
     }
 
+  if (DECL_THREAD_LOCAL_P (decl))
+    /* We don't have a thread-local atexit yet.  FIXME write one using
+       pthread_key_create and friends.  */
+    sorry ("thread-local variable %q#D with non-trivial "
+          "destructor", decl);
+
   /* Call atexit with the cleanup function.  */
   mark_used (cleanup);
   cleanup = build_address (cleanup);
@@ -6797,6 +6789,36 @@ expand_static_init (tree decl, tree init)
       && TYPE_HAS_TRIVIAL_DESTRUCTOR (TREE_TYPE (decl)))
     return;
 
+  if (DECL_THREAD_LOCAL_P (decl) && DECL_GNU_TLS_P (decl)
+      && !DECL_FUNCTION_SCOPE_P (decl))
+    {
+      if (init)
+       error ("non-local variable %qD declared %<__thread%> "
+              "needs dynamic initialization", decl);
+      else
+       error ("non-local variable %qD declared %<__thread%> "
+              "has a non-trivial destructor", decl);
+      static bool informed;
+      if (!informed)
+       {
+         inform (DECL_SOURCE_LOCATION (decl),
+                 "C++11 %<thread_local%> allows dynamic initialization "
+                 "and destruction");
+         informed = true;
+       }
+      return;
+    }
+
+  if (DECL_THREAD_LOCAL_P (decl) && !DECL_FUNCTION_SCOPE_P (decl))
+    {
+      /* We haven't implemented dynamic initialization of non-local
+        thread-local storage yet.  FIXME transform to singleton
+        function.  */
+      sorry ("thread-local variable %qD with dynamic initialization outside "
+            "function scope", decl);
+      return;
+    }
+
   if (DECL_FUNCTION_SCOPE_P (decl))
     {
       /* Emit code to perform this initialization but once.  */
@@ -6804,6 +6826,9 @@ expand_static_init (tree decl, tree init)
       tree then_clause = NULL_TREE, inner_then_clause = NULL_TREE;
       tree guard, guard_addr;
       tree flag, begin;
+      /* We don't need thread-safety code for thread-local vars.  */
+      bool thread_guard = (flag_threadsafe_statics
+                          && !DECL_THREAD_LOCAL_P (decl));
 
       /* Emit code to perform this initialization but once.  This code
         looks like:
@@ -6842,7 +6867,7 @@ expand_static_init (tree decl, tree init)
       /* This optimization isn't safe on targets with relaxed memory
         consistency.  On such targets we force synchronization in
         __cxa_guard_acquire.  */
-      if (!targetm.relaxed_ordering || !flag_threadsafe_statics)
+      if (!targetm.relaxed_ordering || !thread_guard)
        {
          /* Begin the conditional initialization.  */
          if_stmt = begin_if_stmt ();
@@ -6850,7 +6875,7 @@ expand_static_init (tree decl, tree init)
          then_clause = begin_compound_stmt (BCS_NO_SCOPE);
        }
 
-      if (flag_threadsafe_statics)
+      if (thread_guard)
        {
          tree vfntype = NULL_TREE;
          tree acquire_name, release_name, abort_name;
@@ -6908,14 +6933,14 @@ expand_static_init (tree decl, tree init)
 
       finish_expr_stmt (init);
 
-      if (flag_threadsafe_statics)
+      if (thread_guard)
        {
          finish_compound_stmt (inner_then_clause);
          finish_then_clause (inner_if_stmt);
          finish_if_stmt (inner_if_stmt);
        }
 
-      if (!targetm.relaxed_ordering || !flag_threadsafe_statics)
+      if (!targetm.relaxed_ordering || !thread_guard)
        {
          finish_compound_stmt (then_clause);
          finish_then_clause (if_stmt);
@@ -7732,7 +7757,11 @@ grokvardecl (tree type,
     }
 
   if (decl_spec_seq_has_spec_p (declspecs, ds_thread))
-    DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
+    {
+      DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
+      if (declspecs->gnu_thread_keyword_p)
+       DECL_GNU_TLS_P (decl) = true;
+    }
 
   /* If the type of the decl has no linkage, make sure that we'll
      notice that in mark_used.  */
@@ -8462,7 +8491,7 @@ check_var_type (tree identifier, tree type)
 
 tree
 grokdeclarator (const cp_declarator *declarator,
-               const cp_decl_specifier_seq *declspecs,
+               cp_decl_specifier_seq *declspecs,
                enum decl_context decl_context,
                int initialized,
                tree* attrlist)
@@ -9176,9 +9205,15 @@ grokdeclarator (const cp_declarator *declarator,
           && storage_class != sc_extern
           && storage_class != sc_static)
     {
-      error ("function-scope %qs implicitly auto and declared %<__thread%>",
-            name);
-      thread_p = false;
+      if (declspecs->gnu_thread_keyword_p)
+       pedwarn (input_location, 0, "function-scope %qs implicitly auto and "
+                "declared %<__thread%>", name);
+
+      /* When thread_local is applied to a variable of block scope the
+        storage-class-specifier static is implied if it does not appear
+        explicitly.  */
+      storage_class = declspecs->storage_class = sc_static;
+      staticp = 1;
     }
 
   if (storage_class && friendp)
@@ -10454,7 +10489,14 @@ grokdeclarator (const cp_declarator *declarator,
        else if (storage_class == sc_register)
          error ("storage class %<register%> invalid for function %qs", name);
        else if (thread_p)
-         error ("storage class %<__thread%> invalid for function %qs", name);
+         {
+           if (declspecs->gnu_thread_keyword_p)
+             error ("storage class %<__thread%> invalid for function %qs",
+                    name);
+           else
+             error ("storage class %<thread_local%> invalid for function %qs",
+                    name);
+         }
 
         if (virt_specifiers)
           error ("virt-specifiers in %qs not allowed outside a class definition", name);
index a8a2b784c28d8d10a15f6dc27489f650137659a0..193df27c2f8004a9bfec05d810bf06d04c993ae4 100644 (file)
@@ -34,7 +34,7 @@ enum decl_context
 
 /* We need this in here to get the decl_context definition.  */
 extern tree grokdeclarator (const cp_declarator *,
-                           const cp_decl_specifier_seq *,
+                           cp_decl_specifier_seq *,
                            enum decl_context, int, tree*);
 
 /* States indicating how grokdeclarator() should handle declspecs marked
index aad3d0b26f751e861b86b71ccab39281ab999376..f7db1d81b5d905b1fd256a434407a87c0db8a8a6 100644 (file)
@@ -2696,6 +2696,7 @@ get_guard (tree decl)
       TREE_STATIC (guard) = TREE_STATIC (decl);
       DECL_COMMON (guard) = DECL_COMMON (decl);
       DECL_COMDAT (guard) = DECL_COMDAT (decl);
+      DECL_TLS_MODEL (guard) = DECL_TLS_MODEL (decl);
       if (DECL_ONE_ONLY (decl))
        make_decl_one_only (guard, cxx_comdat_group (guard));
       if (TREE_PUBLIC (decl))
index 07f76e39ec6e60316473200f0be88efb261a78f6..52a152d1925cdd69ba85e2727dc734836439f223 100644 (file)
@@ -2248,12 +2248,12 @@ static tree cp_parser_trait_expr
 static bool cp_parser_declares_only_class_p
   (cp_parser *);
 static void cp_parser_set_storage_class
-  (cp_parser *, cp_decl_specifier_seq *, enum rid, location_t);
+  (cp_parser *, cp_decl_specifier_seq *, enum rid, cp_token *);
 static void cp_parser_set_decl_spec_type
-  (cp_decl_specifier_seq *, tree, location_t, bool);
+  (cp_decl_specifier_seq *, tree, cp_token *, bool);
 static void set_and_check_decl_spec_loc
   (cp_decl_specifier_seq *decl_specs,
-   cp_decl_spec ds, source_location location);
+   cp_decl_spec ds, cp_token *);
 static bool cp_parser_friend_p
   (const cp_decl_specifier_seq *);
 static void cp_parser_required_error
@@ -10821,7 +10821,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
 
               /* Set the storage class anyway.  */
               cp_parser_set_storage_class (parser, decl_specs, RID_AUTO,
-                                          token->location);
+                                          token);
             }
           else
            /* C++0x auto type-specifier.  */
@@ -10835,7 +10835,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
          /* Consume the token.  */
          cp_lexer_consume_token (parser->lexer);
           cp_parser_set_storage_class (parser, decl_specs, token->keyword,
-                                      token->location);
+                                      token);
          break;
        case RID_THREAD:
          /* Consume the token.  */
@@ -10855,7 +10855,7 @@ cp_parser_decl_specifier_seq (cp_parser* parser,
        error ("decl-specifier invalid in condition");
 
       if (ds != ds_last)
-       set_and_check_decl_spec_loc (decl_specs, ds, token->location);
+       set_and_check_decl_spec_loc (decl_specs, ds, token);
 
       /* Constructors are a special case.  The `S' in `S()' is not a
         decl-specifier; it is the beginning of the declarator.  */
@@ -11004,7 +11004,7 @@ cp_parser_function_specifier_opt (cp_parser* parser,
   switch (token->keyword)
     {
     case RID_INLINE:
-      set_and_check_decl_spec_loc (decl_specs, ds_inline, token->location);
+      set_and_check_decl_spec_loc (decl_specs, ds_inline, token);
       break;
 
     case RID_VIRTUAL:
@@ -11013,11 +11013,11 @@ cp_parser_function_specifier_opt (cp_parser* parser,
         A member function template shall not be virtual.  */
       if (PROCESSING_REAL_TEMPLATE_DECL_P ())
        error_at (token->location, "templates may not be %<virtual%>");
-      set_and_check_decl_spec_loc (decl_specs, ds_virtual, token->location);
+      set_and_check_decl_spec_loc (decl_specs, ds_virtual, token);
       break;
 
     case RID_EXPLICIT:
-      set_and_check_decl_spec_loc (decl_specs, ds_explicit, token->location);
+      set_and_check_decl_spec_loc (decl_specs, ds_explicit, token);
       break;
 
     default:
@@ -13525,7 +13525,7 @@ cp_parser_type_specifier (cp_parser* parser,
          if (decl_specs)
            cp_parser_set_decl_spec_type (decl_specs,
                                          type_spec,
-                                         token->location,
+                                         token,
                                          /*type_definition_p=*/true);
          return type_spec;
        }
@@ -13554,7 +13554,7 @@ cp_parser_type_specifier (cp_parser* parser,
          if (decl_specs)
            cp_parser_set_decl_spec_type (decl_specs,
                                          type_spec,
-                                         token->location,
+                                         token,
                                          /*type_definition_p=*/true);
          return type_spec;
        }
@@ -13576,7 +13576,7 @@ cp_parser_type_specifier (cp_parser* parser,
       if (decl_specs)
        cp_parser_set_decl_spec_type (decl_specs,
                                      type_spec,
-                                     token->location,
+                                     token,
                                      /*type_definition_p=*/false);
       return type_spec;
 
@@ -13612,7 +13612,7 @@ cp_parser_type_specifier (cp_parser* parser,
     {
       if (decl_specs)
        {
-         set_and_check_decl_spec_loc (decl_specs, ds, token->location);
+         set_and_check_decl_spec_loc (decl_specs, ds, token);
          decl_specs->any_specifiers_p = true;
        }
       return cp_lexer_consume_token (parser->lexer)->u.value;
@@ -13703,7 +13703,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       type = boolean_type_node;
       break;
     case RID_SHORT:
-      set_and_check_decl_spec_loc (decl_specs, ds_short, token->location);
+      set_and_check_decl_spec_loc (decl_specs, ds_short, token);
       type = short_integer_type_node;
       break;
     case RID_INT:
@@ -13720,15 +13720,15 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       break;
     case RID_LONG:
       if (decl_specs)
-       set_and_check_decl_spec_loc (decl_specs, ds_long, token->location);
+       set_and_check_decl_spec_loc (decl_specs, ds_long, token);
       type = long_integer_type_node;
       break;
     case RID_SIGNED:
-      set_and_check_decl_spec_loc (decl_specs, ds_signed, token->location);
+      set_and_check_decl_spec_loc (decl_specs, ds_signed, token);
       type = integer_type_node;
       break;
     case RID_UNSIGNED:
-      set_and_check_decl_spec_loc (decl_specs, ds_unsigned, token->location);
+      set_and_check_decl_spec_loc (decl_specs, ds_unsigned, token);
       type = unsigned_type_node;
       break;
     case RID_FLOAT:
@@ -13766,7 +13766,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
 
       if (decl_specs)
        cp_parser_set_decl_spec_type (decl_specs, type,
-                                     token->location,
+                                     token,
                                      /*type_definition_p=*/false);
 
       return type;
@@ -13775,7 +13775,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       type = cp_parser_trait_expr (parser, RID_UNDERLYING_TYPE);
       if (decl_specs)
        cp_parser_set_decl_spec_type (decl_specs, type,
-                                     token->location,
+                                     token,
                                      /*type_definition_p=*/false);
 
       return type;
@@ -13785,7 +13785,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       type = cp_parser_trait_expr (parser, token->keyword);
       if (decl_specs)
        cp_parser_set_decl_spec_type (decl_specs, type,
-                                     token->location,
+                                     token,
                                      /*type_definition_p=*/false);
       return type;
     default:
@@ -13800,7 +13800,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       type = token->u.value;
       if (decl_specs)
        cp_parser_set_decl_spec_type (decl_specs, type,
-                                     token->location,
+                                     token,
                                      /*type_definition_p=*/false);
       cp_lexer_consume_token (parser->lexer);
       return type;
@@ -13817,7 +13817,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
              && token->keyword != RID_LONG))
        cp_parser_set_decl_spec_type (decl_specs,
                                      type,
-                                     token->location,
+                                     token,
                                      /*type_definition_p=*/false);
       if (decl_specs)
        decl_specs->any_specifiers_p = true;
@@ -13894,7 +13894,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
        type = NULL_TREE;
       if (type && decl_specs)
        cp_parser_set_decl_spec_type (decl_specs, type,
-                                     token->location,
+                                     token,
                                      /*type_definition_p=*/false);
     }
 
@@ -15245,21 +15245,24 @@ static tree
 cp_parser_alias_declaration (cp_parser* parser)
 {
   tree id, type, decl, pushed_scope = NULL_TREE, attributes;
-  location_t id_location, using_location, attrs_location = 0;
+  location_t id_location;
   cp_declarator *declarator;
   cp_decl_specifier_seq decl_specs;
   bool member_p;
   const char *saved_message = NULL;
 
   /* Look for the `using' keyword.  */
-  using_location = cp_lexer_peek_token (parser->lexer)->location;
-  cp_parser_require_keyword (parser, RID_USING, RT_USING);
+  cp_token *using_token
+    = cp_parser_require_keyword (parser, RID_USING, RT_USING);
+  if (using_token == NULL)
+    return error_mark_node;
+
   id_location = cp_lexer_peek_token (parser->lexer)->location;
   id = cp_parser_identifier (parser);
   if (id == error_mark_node)
     return error_mark_node;
 
-  attrs_location = cp_lexer_peek_token (parser->lexer)->location;
+  cp_token *attrs_token = cp_lexer_peek_token (parser->lexer);
   attributes = cp_parser_attributes_opt (parser);
   if (attributes == error_mark_node)
     return error_mark_node;
@@ -15316,14 +15319,14 @@ cp_parser_alias_declaration (cp_parser* parser)
       decl_specs.attributes = attributes;
       set_and_check_decl_spec_loc (&decl_specs,
                                   ds_attribute,
-                                  attrs_location);
+                                  attrs_token);
     }
   set_and_check_decl_spec_loc (&decl_specs,
                               ds_typedef,
-                              using_location);
+                              using_token);
   set_and_check_decl_spec_loc (&decl_specs,
                               ds_alias,
-                              using_location);
+                              using_token);
 
   declarator = make_id_declarator (NULL_TREE, id, sfk_none);
   declarator->id_loc = id_location;
@@ -22585,13 +22588,13 @@ static void
 cp_parser_set_storage_class (cp_parser *parser,
                             cp_decl_specifier_seq *decl_specs,
                             enum rid keyword,
-                            location_t location)
+                            cp_token *token)
 {
   cp_storage_class storage_class;
 
   if (parser->in_unbraced_linkage_specification_p)
     {
-      error_at (location, "invalid use of %qD in linkage specification",
+      error_at (token->location, "invalid use of %qD in linkage specification",
                ridpointers[keyword]);
       return;
     }
@@ -22602,11 +22605,11 @@ cp_parser_set_storage_class (cp_parser *parser,
     }
 
   if ((keyword == RID_EXTERN || keyword == RID_STATIC)
-      && decl_spec_seq_has_spec_p (decl_specs, ds_thread))
+      && decl_spec_seq_has_spec_p (decl_specs, ds_thread)
+      && decl_specs->gnu_thread_keyword_p)
     {
-      error_at (decl_specs->locations[ds_thread],
+      pedwarn (decl_specs->locations[ds_thread], 0,
                "%<__thread%> before %qD", ridpointers[keyword]);
-      decl_specs->locations[ds_thread] = 0;
     }
 
   switch (keyword)
@@ -22630,7 +22633,7 @@ cp_parser_set_storage_class (cp_parser *parser,
       gcc_unreachable ();
     }
   decl_specs->storage_class = storage_class;
-  set_and_check_decl_spec_loc (decl_specs, ds_storage_class, location);
+  set_and_check_decl_spec_loc (decl_specs, ds_storage_class, token);
 
   /* A storage class specifier cannot be applied alongside a typedef 
      specifier. If there is a typedef specifier present then set 
@@ -22646,7 +22649,7 @@ cp_parser_set_storage_class (cp_parser *parser,
 static void
 cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs,
                              tree type_spec,
-                             location_t location,
+                             cp_token *token,
                              bool type_definition_p)
 {
   decl_specs->any_specifiers_p = true;
@@ -22671,12 +22674,12 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs,
       decl_specs->redefined_builtin_type = type_spec;
       set_and_check_decl_spec_loc (decl_specs,
                                   ds_redefined_builtin_type_spec,
-                                  location);
+                                  token);
       if (!decl_specs->type)
        {
          decl_specs->type = type_spec;
          decl_specs->type_definition_p = false;
-         set_and_check_decl_spec_loc (decl_specs,ds_type_spec, location);
+         set_and_check_decl_spec_loc (decl_specs,ds_type_spec, token);
        }
     }
   else if (decl_specs->type)
@@ -22686,10 +22689,19 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs,
       decl_specs->type = type_spec;
       decl_specs->type_definition_p = type_definition_p;
       decl_specs->redefined_builtin_type = NULL_TREE;
-      set_and_check_decl_spec_loc (decl_specs, ds_type_spec, location);
+      set_and_check_decl_spec_loc (decl_specs, ds_type_spec, token);
     }
 }
 
+/* True iff TOKEN is the GNU keyword __thread.  */
+
+static bool
+token_is__thread (cp_token *token)
+{
+  gcc_assert (token->keyword == RID_THREAD);
+  return !strcmp (IDENTIFIER_POINTER (token->u.value), "__thread");
+}
+
 /* Set the location for a declarator specifier and check if it is
    duplicated.
 
@@ -22704,15 +22716,21 @@ cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs,
 
 static void
 set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
-                            cp_decl_spec ds, source_location location)
+                            cp_decl_spec ds, cp_token *token)
 {
   gcc_assert (ds < ds_last);
 
   if (decl_specs == NULL)
     return;
 
+  source_location location = token->location;
+
   if (decl_specs->locations[ds] == 0)
-    decl_specs->locations[ds] = location;
+    {
+      decl_specs->locations[ds] = location;
+      if (ds == ds_thread)
+       decl_specs->gnu_thread_keyword_p = token_is__thread (token);
+    }
   else
     {
       if (ds == ds_long)
@@ -22728,6 +22746,15 @@ set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
                             "ISO C++ 1998 does not support %<long long%>");
            }
        }
+      else if (ds == ds_thread)
+       {
+         bool gnu = token_is__thread (token);
+         if (gnu != decl_specs->gnu_thread_keyword_p)
+           error_at (location,
+                     "both %<__thread%> and %<thread_local%> specified");
+         else
+           error_at (location, "duplicate %qD", token->u.value);
+       }
       else
        {
          static const char *const decl_spec_names[] = {
@@ -22745,8 +22772,7 @@ set_and_check_decl_spec_loc (cp_decl_specifier_seq *decl_specs,
            "typedef",
            "using",
             "constexpr",
-           "__complex",
-           "__thread"
+           "__complex"
          };
          error_at (location,
                    "duplicate %qs", decl_spec_names[ds]);
@@ -24587,7 +24613,7 @@ cp_parser_objc_class_ivars (cp_parser* parser)
          declspecs.storage_class = sc_none;
        }
 
-      /* __thread.  */
+      /* thread_local.  */
       if (decl_spec_seq_has_spec_p (&declspecs, ds_thread))
        {
          cp_parser_error (parser, "invalid type for instance variable");
@@ -25166,7 +25192,7 @@ cp_parser_objc_struct_declaration (cp_parser *parser)
       declspecs.storage_class = sc_none;
     }
   
-  /* __thread.  */
+  /* thread_local.  */
   if (decl_spec_seq_has_spec_p (&declspecs, ds_thread))
     {
       cp_parser_error (parser, "invalid type for property");
index 1eb751ed9b7158048c7a351a6e1f200aa53aa1ed..76d0762e829ae11fd4979ba33deacd87589faa50 100644 (file)
@@ -1,3 +1,10 @@
+2012-10-08  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/tls/init-2.C: Tweak errors.
+       * g++.dg/tls/thread_local1.C: New.
+       * g++.dg/tls/thread_local2.C: New.
+       * g++.dg/tls/thread_local7.C: New.
+
 2012-10-08  Oleg Endo  <olegendo@gcc.gnu.org>
 
        PR target/54685
index c9f646d3a1d93db2f4f1dbd71ea5304131be0fb5..327c309e98584e5b22a88fb63c026b8a2ab1f6bf 100644 (file)
@@ -2,13 +2,13 @@
 /* { dg-require-effective-target tls } */
 
 extern __thread int i;
-__thread int *p = &i;  /* { dg-error "dynamically initialized" } */
+__thread int *p = &i;  /* { dg-error "dynamic initialization" } */
 
 extern int f();
-__thread int j = f();  /* { dg-error "dynamically initialized" } */
+__thread int j = f();  /* { dg-error "dynamic initialization" } */
 
 struct S
 {
   S();
 };
-__thread S s;          /* { dg-error "" } two errors here */
+__thread S s;          /* { dg-error "dynamic initialization" } */
diff --git a/gcc/testsuite/g++.dg/tls/thread_local1.C b/gcc/testsuite/g++.dg/tls/thread_local1.C
new file mode 100644 (file)
index 0000000..e7734a0
--- /dev/null
@@ -0,0 +1,21 @@
+// { dg-options "-std=c++11" }
+// { dg-require-effective-target tls }
+
+// The variable should have a guard.
+// { dg-final { scan-assembler "_ZGVZ1fvE1a" } }
+// But since it's thread local we don't need to guard against
+// simultaneous execution.
+// { dg-final { scan-assembler-not "cxa_guard" } }
+// The guard should be TLS, not local common.
+// { dg-final { scan-assembler-not "\.comm" } }
+
+struct A
+{
+  A();
+};
+
+A &f()
+{
+  thread_local A a;
+  return a;
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local2.C b/gcc/testsuite/g++.dg/tls/thread_local2.C
new file mode 100644 (file)
index 0000000..4cbef15
--- /dev/null
@@ -0,0 +1,27 @@
+// { dg-do run }
+// { dg-options "-std=c++11" }
+// { dg-require-effective-target tls_runtime }
+
+extern "C" void abort();
+
+struct A
+{
+  A();
+  int i;
+};
+
+A &f()
+{
+  thread_local A a;
+  return a;
+}
+
+int j;
+A::A(): i(j) { }
+
+int main()
+{
+  j = 42;
+  if (f().i != 42)
+    abort ();
+}
diff --git a/gcc/testsuite/g++.dg/tls/thread_local7.C b/gcc/testsuite/g++.dg/tls/thread_local7.C
new file mode 100644 (file)
index 0000000..77a1c05
--- /dev/null
@@ -0,0 +1,10 @@
+// { dg-options "-std=c++11" }
+// { dg-require-effective-target tls }
+
+// The reference temp should be TLS, not normal data.
+// { dg-final { scan-assembler-not "\\.data" } }
+
+void f()
+{
+  thread_local int&& ir = 42;
+}