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
This commit is contained in:
parent
e9dc054758
commit
582d9b50ed
|
@ -1,3 +1,7 @@
|
|||
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>
|
||||
|
||||
* c-common.c (atomic_size_supported_p): New function.
|
||||
|
|
|
@ -424,6 +424,7 @@ const struct c_common_resword c_common_reswords[] =
|
|||
{ "_Static_assert", RID_STATIC_ASSERT, D_CONLY },
|
||||
{ "_Noreturn", RID_NORETURN, D_CONLY },
|
||||
{ "_Generic", RID_GENERIC, D_CONLY },
|
||||
{ "_Thread_local", RID_THREAD, D_CONLY },
|
||||
{ "__FUNCTION__", RID_FUNCTION_NAME, 0 },
|
||||
{ "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
|
||||
{ "__alignof", RID_ALIGNOF, 0 },
|
||||
|
|
|
@ -1,3 +1,16 @@
|
|||
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>
|
||||
Andrew MacLeod <amacleod@redhat.com>
|
||||
|
||||
|
|
|
@ -3805,7 +3805,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -5164,7 +5165,8 @@ grokdeclarator (const struct c_declarator *declarator,
|
|||
if (storage_class == csc_typedef)
|
||||
error_at (loc, "function definition declared %<typedef%>");
|
||||
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;
|
||||
if (storage_class == csc_auto
|
||||
|| storage_class == csc_register
|
||||
|
@ -5233,8 +5235,8 @@ grokdeclarator (const struct c_declarator *declarator,
|
|||
else if (threadp && storage_class == csc_none)
|
||||
{
|
||||
error_at (loc, "function-scope %qE implicitly auto and declared "
|
||||
"%<__thread%>",
|
||||
name);
|
||||
"%qs", name,
|
||||
declspecs->thread_gnu_p ? "__thread" : "_Thread_local");
|
||||
threadp = false;
|
||||
}
|
||||
}
|
||||
|
@ -8980,6 +8982,7 @@ build_null_declspecs (void)
|
|||
ret->inline_p = false;
|
||||
ret->noreturn_p = false;
|
||||
ret->thread_p = false;
|
||||
ret->thread_gnu_p = false;
|
||||
ret->const_p = false;
|
||||
ret->volatile_p = false;
|
||||
ret->atomic_p = false;
|
||||
|
@ -9773,14 +9776,29 @@ declspecs_add_scspec (source_location loc,
|
|||
case RID_THREAD:
|
||||
dupe = specs->thread_p;
|
||||
if (specs->storage_class == csc_auto)
|
||||
error ("%<__thread%> used with %<auto%>");
|
||||
error ("%qE used with %<auto%>", scspec);
|
||||
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)
|
||||
error ("%<__thread%> used with %<typedef%>");
|
||||
error ("%qE used with %<typedef%>", scspec);
|
||||
else
|
||||
{
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -9790,7 +9808,7 @@ declspecs_add_scspec (source_location loc,
|
|||
case RID_EXTERN:
|
||||
n = csc_extern;
|
||||
/* Diagnose "__thread extern". */
|
||||
if (specs->thread_p)
|
||||
if (specs->thread_p && specs->thread_gnu_p)
|
||||
error ("%<__thread%> before %<extern%>");
|
||||
break;
|
||||
case RID_REGISTER:
|
||||
|
@ -9799,7 +9817,7 @@ declspecs_add_scspec (source_location loc,
|
|||
case RID_STATIC:
|
||||
n = csc_static;
|
||||
/* Diagnose "__thread static". */
|
||||
if (specs->thread_p)
|
||||
if (specs->thread_p && specs->thread_gnu_p)
|
||||
error ("%<__thread%> before %<static%>");
|
||||
break;
|
||||
case RID_TYPEDEF:
|
||||
|
@ -9811,7 +9829,12 @@ declspecs_add_scspec (source_location loc,
|
|||
if (n != csc_none && n == specs->storage_class)
|
||||
dupe = true;
|
||||
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 (specs->storage_class != csc_none && n != specs->storage_class)
|
||||
|
@ -9824,7 +9847,9 @@ declspecs_add_scspec (source_location loc,
|
|||
specs->locations[cdw_storage_class] = loc;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1969,6 +1969,9 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser)
|
|||
static
|
||||
auto
|
||||
register
|
||||
_Thread_local
|
||||
|
||||
(_Thread_local is new in C11.)
|
||||
|
||||
C99 6.7.4:
|
||||
function-specifier:
|
||||
|
|
|
@ -320,8 +320,10 @@ struct c_declspecs {
|
|||
BOOL_BITFIELD inline_p : 1;
|
||||
/* Whether "_Noreturn" was speciied. */
|
||||
BOOL_BITFIELD noreturn_p : 1;
|
||||
/* Whether "__thread" was specified. */
|
||||
/* Whether "__thread" or "_Thread_local" was specified. */
|
||||
BOOL_BITFIELD thread_p : 1;
|
||||
/* Whether "__thread" rather than "_Thread_local" was specified. */
|
||||
BOOL_BITFIELD thread_gnu_p : 1;
|
||||
/* Whether "const" was specified. */
|
||||
BOOL_BITFIELD const_p : 1;
|
||||
/* Whether "volatile" was specified. */
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
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>
|
||||
|
||||
* gnat.dg/aggr21.adb: New test.
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/* 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];
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/* 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" } */
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
/* 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" } */
|
|
@ -0,0 +1,5 @@
|
|||
/* 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 @@
|
|||
|
||||
__thread extern int g1; /* { dg-error "'__thread' before 'extern'" } */
|
||||
__thread static int g2; /* { dg-error "'__thread' before 'static'" } */
|
||||
__thread __thread int g3; /* { dg-error "duplicate '__thread'" } */
|
||||
__thread __thread int g3; /* { dg-error "duplicate" } */
|
||||
typedef __thread int g4; /* { dg-error "'__thread' used with 'typedef'" } */
|
||||
|
||||
void foo()
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
__thread extern int g1; /* { dg-error "'__thread' before 'extern'" } */
|
||||
__thread static int g2; /* { dg-error "'__thread' before 'static'" } */
|
||||
__thread __thread int g3; /* { dg-error "duplicate '__thread'" } */
|
||||
__thread __thread int g3; /* { dg-error "duplicate" } */
|
||||
typedef __thread int g4; /* { dg-error " '__thread' used with 'typedef'" } */
|
||||
|
||||
void foo()
|
||||
|
|
Loading…
Reference in New Issue