From 3740094cceb135dd9807b3faa60ecf30c50a2ea0 Mon Sep 17 00:00:00 2001 From: jason Date: Mon, 8 Oct 2012 14:45:12 +0000 Subject: [PATCH] Partial implementation of C++11 thread_local. 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192209 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/c-family/ChangeLog | 4 ++ gcc/c-family/c-common.c | 1 + gcc/cp/ChangeLog | 22 ++++++ gcc/cp/call.c | 12 ++-- gcc/cp/cp-tree.h | 8 +++ gcc/cp/decl.c | 90 ++++++++++++++++------- gcc/cp/decl.h | 2 +- gcc/cp/decl2.c | 1 + gcc/cp/parser.c | 118 +++++++++++++++++++------------ gcc/testsuite/ChangeLog | 7 ++ gcc/testsuite/g++.dg/tls/init-2.C | 6 +- gcc/testsuite/g++.dg/tls/thread_local1.C | 21 ++++++ gcc/testsuite/g++.dg/tls/thread_local2.C | 27 +++++++ gcc/testsuite/g++.dg/tls/thread_local7.C | 10 +++ 14 files changed, 250 insertions(+), 79 deletions(-) create mode 100644 gcc/testsuite/g++.dg/tls/thread_local1.C create mode 100644 gcc/testsuite/g++.dg/tls/thread_local2.C create mode 100644 gcc/testsuite/g++.dg/tls/thread_local7.C diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index b49388df86d..36bab2ee23e 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,7 @@ +2012-10-08 Jason Merrill + + * c-common.c (c_common_reswords): Add thread_local. + 2012-10-08 Dodji Seketeli PR c++/53528 C++11 attribute support diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index e24278951da..bb18c39cd6b 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -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 }, diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 660a2199c8f..871dbaa8530 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,25 @@ +2012-10-08 Jason Merrill + + 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 PR c++/53528 C++11 attribute support diff --git a/gcc/cp/call.c b/gcc/cp/call.c index f58dc8a52e0..9c8de39e92d 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index a1d44240189..51c8d566e90 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 2848ad5b7be..b409c34eee1 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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 % 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 % 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 % invalid for function %qs", + name); + } if (virt_specifiers) error ("virt-specifiers in %qs not allowed outside a class definition", name); diff --git a/gcc/cp/decl.h b/gcc/cp/decl.h index a8a2b784c28..193df27c2f8 100644 --- a/gcc/cp/decl.h +++ b/gcc/cp/decl.h @@ -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 diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index aad3d0b26f7..f7db1d81b5d 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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)) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 07f76e39ec6..52a152d1925 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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 %"); - 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 %"); } } + 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 % 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"); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 1eb751ed9b7..76d0762e829 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2012-10-08 Jason Merrill + + * 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 PR target/54685 diff --git a/gcc/testsuite/g++.dg/tls/init-2.C b/gcc/testsuite/g++.dg/tls/init-2.C index c9f646d3a1d..327c309e985 100644 --- a/gcc/testsuite/g++.dg/tls/init-2.C +++ b/gcc/testsuite/g++.dg/tls/init-2.C @@ -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 index 00000000000..e7734a0badf --- /dev/null +++ b/gcc/testsuite/g++.dg/tls/thread_local1.C @@ -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 index 00000000000..4cbef155ead --- /dev/null +++ b/gcc/testsuite/g++.dg/tls/thread_local2.C @@ -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 index 00000000000..77a1c05e44c --- /dev/null +++ b/gcc/testsuite/g++.dg/tls/thread_local7.C @@ -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; +} -- 2.11.4.GIT