aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/c-family/ChangeLog4
-rw-r--r--gcc/c-family/c-common.c1
-rw-r--r--gcc/cp/ChangeLog22
-rw-r--r--gcc/cp/call.c12
-rw-r--r--gcc/cp/cp-tree.h8
-rw-r--r--gcc/cp/decl.c90
-rw-r--r--gcc/cp/decl.h2
-rw-r--r--gcc/cp/decl2.c1
-rw-r--r--gcc/cp/parser.c118
-rw-r--r--gcc/testsuite/ChangeLog7
-rw-r--r--gcc/testsuite/g++.dg/tls/init-2.C6
-rw-r--r--gcc/testsuite/g++.dg/tls/thread_local1.C21
-rw-r--r--gcc/testsuite/g++.dg/tls/thread_local2.C27
-rw-r--r--gcc/testsuite/g++.dg/tls/thread_local7.C10
14 files changed, 250 insertions, 79 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index b49388d..36bab2e 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -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
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index e242789..bb18c39 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 660a219..871dbaa 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index f58dc8a..9c8de39 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 a1d4424..51c8d56 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 2848ad5..b409c34 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 %<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);
diff --git a/gcc/cp/decl.h b/gcc/cp/decl.h
index a8a2b78..193df27 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 aad3d0b..f7db1d8 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 07f76e3..52a152d 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 %<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");
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 1eb751e..76d0762 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/g++.dg/tls/init-2.C b/gcc/testsuite/g++.dg/tls/init-2.C
index c9f646d..327c309 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 0000000..e7734a0
--- /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 0000000..4cbef15
--- /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 0000000..77a1c05
--- /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;
+}