diff options
-rw-r--r-- | gcc/c-family/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/c-family/c-common.c | 1 | ||||
-rw-r--r-- | gcc/c/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/c/c-decl.c | 47 | ||||
-rw-r--r-- | gcc/c/c-parser.c | 3 | ||||
-rw-r--r-- | gcc/c/c-tree.h | 4 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/c11-thread-local-1.c | 28 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/c11-thread-local-2.c | 46 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/c90-thread-local-1.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/c99-thread-local-1.c | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tls/diag-2.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/objc.dg/tls/diag-2.m | 2 |
13 files changed, 154 insertions, 14 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 6b2a5ab..1a38bd4 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -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. diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 93481b9..1c31743 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -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 }, diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index e38bcb8..1cf5883 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -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> diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 9520e4d..6fe418e 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -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; } } diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 09cce1c..5b4665a 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -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: diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 8dffa9c..502fdca 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -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. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 290af4e..d3be7aa 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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. diff --git a/gcc/testsuite/gcc.dg/c11-thread-local-1.c b/gcc/testsuite/gcc.dg/c11-thread-local-1.c new file mode 100644 index 0000000..b21209a --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-thread-local-1.c @@ -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]; +} diff --git a/gcc/testsuite/gcc.dg/c11-thread-local-2.c b/gcc/testsuite/gcc.dg/c11-thread-local-2.c new file mode 100644 index 0000000..3387226 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c11-thread-local-2.c @@ -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" } */ +} diff --git a/gcc/testsuite/gcc.dg/c90-thread-local-1.c b/gcc/testsuite/gcc.dg/c90-thread-local-1.c new file mode 100644 index 0000000..92bf57a --- /dev/null +++ b/gcc/testsuite/gcc.dg/c90-thread-local-1.c @@ -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" } */ diff --git a/gcc/testsuite/gcc.dg/c99-thread-local-1.c b/gcc/testsuite/gcc.dg/c99-thread-local-1.c new file mode 100644 index 0000000..ff53125 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c99-thread-local-1.c @@ -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" } */ diff --git a/gcc/testsuite/gcc.dg/tls/diag-2.c b/gcc/testsuite/gcc.dg/tls/diag-2.c index 8276cb3..8548243 100644 --- a/gcc/testsuite/gcc.dg/tls/diag-2.c +++ b/gcc/testsuite/gcc.dg/tls/diag-2.c @@ -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() diff --git a/gcc/testsuite/objc.dg/tls/diag-2.m b/gcc/testsuite/objc.dg/tls/diag-2.m index 4f22281..58cca01 100644 --- a/gcc/testsuite/objc.dg/tls/diag-2.m +++ b/gcc/testsuite/objc.dg/tls/diag-2.m @@ -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() |