Commit 582d9b50 by Joseph Myers Committed by Joseph Myers

c-common.c (c_common_reswords): Add _Thread_local.

c-family:
	* c-common.c (c_common_reswords): Add _Thread_local.

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

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

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