From 7a1f3f5f3bdf7862391b3404eaaf348364ba57bd Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Wed, 22 May 2002 16:42:57 -0700 Subject: decl.c (check_tag_decl): Handle RID_THREAD. * decl.c (check_tag_decl): Handle RID_THREAD. (obscure_complex_init): Reject run-time init of tls. (grokvardecl, grokdeclarator): Handle RID_THREAD. * lex.c (reswords): Add __thread. (rid_to_yy): Map RID_THREAD to SCSPEC. * g++.dg/dg.exp: Prune the tls subdirectory. * g++.dg/tls/tls.exp, g++.dg/tls/trivial.C: New. * g++.dg/tls/diag-1.C, g++.dg/tls/diag-2.C: New. * g++.dg/tls/init-1.C: New. From-SVN: r53754 --- gcc/cp/ChangeLog | 8 ++++++ gcc/cp/decl.c | 50 +++++++++++++++++++++++++++++++++++++- gcc/cp/lex.c | 3 ++- gcc/testsuite/ChangeLog | 21 ++++++++++------ gcc/testsuite/g++.dg/dg.exp | 9 ++++--- gcc/testsuite/g++.dg/tls/diag-1.C | 30 +++++++++++++++++++++++ gcc/testsuite/g++.dg/tls/diag-2.C | 25 +++++++++++++++++++ gcc/testsuite/g++.dg/tls/init-1.C | 13 ++++++++++ gcc/testsuite/g++.dg/tls/init-2.C | 13 ++++++++++ gcc/testsuite/g++.dg/tls/tls.exp | 44 +++++++++++++++++++++++++++++++++ gcc/testsuite/g++.dg/tls/trivial.C | 1 + 11 files changed, 204 insertions(+), 13 deletions(-) create mode 100644 gcc/testsuite/g++.dg/tls/diag-1.C create mode 100644 gcc/testsuite/g++.dg/tls/diag-2.C create mode 100644 gcc/testsuite/g++.dg/tls/init-1.C create mode 100644 gcc/testsuite/g++.dg/tls/init-2.C create mode 100644 gcc/testsuite/g++.dg/tls/tls.exp create mode 100644 gcc/testsuite/g++.dg/tls/trivial.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9a2e55e..69008fd 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2002-05-22 Richard Henderson + + * decl.c (check_tag_decl): Handle RID_THREAD. + (obscure_complex_init): Reject run-time init of tls. + (grokvardecl, grokdeclarator): Handle RID_THREAD. + * lex.c (reswords): Add __thread. + (rid_to_yy): Map RID_THREAD to SCSPEC. + 2002-05-22 Neil Booth * cp-lang.c (LANG_HOOKS_POST_OPTIONS): Use c_common_post_options. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6c5b979..dbdc6f2 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -7106,7 +7106,8 @@ check_tag_decl (declspecs) || value == ridpointers[(int) RID_VIRTUAL] || value == ridpointers[(int) RID_CONST] || value == ridpointers[(int) RID_VOLATILE] - || value == ridpointers[(int) RID_EXPLICIT]) + || value == ridpointers[(int) RID_EXPLICIT] + || value == ridpointers[(int) RID_THREAD]) ob_modifier = value; } @@ -7580,6 +7581,12 @@ static tree obscure_complex_init (decl, init) tree decl, init; { + if (DECL_THREAD_LOCAL (decl)) + { + error ("run-time initialization of thread-local storage"); + return NULL_TREE; + } + if (! flag_no_inline && TREE_STATIC (decl)) { if (extract_init (decl, init)) @@ -9274,6 +9281,16 @@ grokvardecl (type, declarator, specbits_in, initialized, constp, in_namespace) TREE_PUBLIC (decl) = DECL_EXTERNAL (decl); } + if (RIDBIT_SETP (RID_THREAD, specbits)) + { + if (targetm.have_tls) + DECL_THREAD_LOCAL (decl) = 1; + else + /* A mere warning is sure to result in improper semantics + at runtime. Don't bother to allow this to compile. */ + error ("thread-local storage not supported for this target"); + } + if (TREE_PUBLIC (decl)) { /* [basic.link]: A name with no linkage (notably, the name of a class @@ -10176,10 +10193,22 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) } else if (RIDBIT_SETP (i, specbits)) pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id)); + + /* Diagnose "__thread extern". Recall that this list + is in the reverse order seen in the text. */ + if (i == (int)RID_THREAD) + { + if (RIDBIT_SETP (RID_EXTERN, specbits)) + error ("`__thread' before `extern'"); + if (RIDBIT_SETP (RID_STATIC, specbits)) + error ("`__thread' before `static'"); + } + if (i == (int)RID_EXTERN && TREE_PURPOSE (spec) == error_mark_node) /* This extern was part of a language linkage. */ extern_langp = 1; + RIDBIT_SET (i, specbits); goto found; } @@ -10476,6 +10505,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) { if (RIDBIT_SETP (RID_STATIC, specbits)) nclasses++; if (RIDBIT_SETP (RID_EXTERN, specbits) && !extern_langp) nclasses++; + if (RIDBIT_SETP (RID_THREAD, specbits)) nclasses++; if (decl_context == PARM && nclasses > 0) error ("storage class specifiers invalid in parameter declarations"); if (RIDBIT_SETP (RID_TYPEDEF, specbits)) @@ -10507,6 +10537,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) /* Warn about storage classes that are invalid for certain kinds of declarations (parameters, typenames, etc.). */ + /* "static __thread" and "extern __thread" are allowed. */ + if (nclasses == 2 + && RIDBIT_SETP (RID_THREAD, specbits) + && (RIDBIT_SETP (RID_EXTERN, specbits) + || RIDBIT_SETP (RID_STATIC, specbits))) + nclasses = 1; + if (nclasses > 1) error ("multiple storage classes in declaration of `%s'", name); else if (decl_context != NORMAL && nclasses > 0) @@ -10562,6 +10599,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) RIDBIT_RESET (RID_REGISTER, specbits); RIDBIT_RESET (RID_AUTO, specbits); RIDBIT_RESET (RID_EXTERN, specbits); + RIDBIT_RESET (RID_THREAD, specbits); } } else if (RIDBIT_SETP (RID_EXTERN, specbits) && initialized && !funcdef_flag) @@ -10584,6 +10622,14 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist) if (RIDBIT_SETP (RID_AUTO, specbits)) error ("top-level declaration of `%s' specifies `auto'", name); } + else if (RIDBIT_SETP (RID_THREAD, specbits) + && !RIDBIT_SETP (RID_EXTERN, specbits) + && !RIDBIT_SETP (RID_STATIC, specbits)) + { + error ("function-scope `%s' implicitly auto and declared `__thread'", + name); + RIDBIT_RESET (RID_THREAD, specbits); + } if (nclasses > 0 && friendp) error ("storage class specifiers invalid in friend function declarations"); @@ -11784,6 +11830,8 @@ friend declaration requires class-key, i.e. `friend %#T'", error ("storage class `auto' invalid for function `%s'", name); else if (RIDBIT_SETP (RID_REGISTER, specbits)) error ("storage class `register' invalid for function `%s'", name); + else if (RIDBIT_SETP (RID_THREAD, specbits)) + error ("storage class `__thread' invalid for function `%s'", name); /* Function declaration not at top level. Storage classes other than `extern' are not allowed diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index 91931d4..a2b0dd3 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -362,6 +362,7 @@ static const struct resword reswords[] = { "__restrict__", RID_RESTRICT, 0 }, { "__signed", RID_SIGNED, 0 }, { "__signed__", RID_SIGNED, 0 }, + { "__thread", RID_THREAD, 0 }, { "__typeof", RID_TYPEOF, 0 }, { "__typeof__", RID_TYPEOF, 0 }, { "__volatile", RID_VOLATILE, 0 }, @@ -467,7 +468,7 @@ const short rid_to_yy[RID_MAX] = /* RID_BOUNDED */ 0, /* RID_UNBOUNDED */ 0, /* RID_COMPLEX */ TYPESPEC, - /* RID_THREAD */ 0, + /* RID_THREAD */ SCSPEC, /* C++ */ /* RID_FRIEND */ SCSPEC, diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index eb45471..9807295 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2002-05-22 Richard Henderson + + * g++.dg/dg.exp: Prune the tls subdirectory. + * g++.dg/tls/tls.exp, g++.dg/tls/trivial.C: New. + * g++.dg/tls/diag-1.C, g++.dg/tls/diag-2.C: New. + * g++.dg/tls/init-1.C: New. + 2002-05-22 Jakub Jelinek * gcc.dg/20020517-1.c: New test. @@ -168,11 +175,11 @@ Mon May 20 10:51:35 2002 J"orn Rennecke 2002-05-02 Aldy Hernandez - * gcc.dg/altivec-8.c: New. + * gcc.dg/altivec-8.c: New. 2002-05-01 Aldy Hernandez - * gcc.dg/altivec-7.c: New. + * gcc.dg/altivec-7.c: New. 2002-04-29 Jakub Jelinek @@ -319,8 +326,8 @@ Wed Apr 24 21:38:36 2002 J"orn Rennecke 2002-04-18 Richard Henderson - * gcc.dg/20000906-1.c: Enable for all targets. - * gcc.c-torture/compile/iftrap-2.c: New. + * gcc.dg/20000906-1.c: Enable for all targets. + * gcc.c-torture/compile/iftrap-2.c: New. 2002-04-18 Jakub Jelinek @@ -329,9 +336,9 @@ Wed Apr 24 21:38:36 2002 J"orn Rennecke 2002-04-18 Richard Henderson - * gcc.c-torture/compile/iftrap-1.c: New. - * gcc.dg/iftrap-1.c: Adjust for ia64. - * gcc.dg/iftrap-2.c: New. + * gcc.c-torture/compile/iftrap-1.c: New. + * gcc.dg/iftrap-1.c: Adjust for ia64. + * gcc.dg/iftrap-2.c: New. 2002-04-18 Jakub Jelinek diff --git a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp index b59d302..da499be 100644 --- a/gcc/testsuite/g++.dg/dg.exp +++ b/gcc/testsuite/g++.dg/dg.exp @@ -31,10 +31,11 @@ dg-init # Gather a list of all tests, with the exception of those in directories # that are handled specially. set all [lsort [find $srcdir/$subdir *.C]] -set tests [prune [prune [prune [prune $all $srcdir/$subdir/special/*] \ - $srcdir/$subdir/debug/*] \ - $srcdir/$subdir/gcov/*] \ - $srcdir/$subdir/bprob/*] +set tests [prune $tests $srcdir/$subdir/bprob/*] +set tests [prune $tests $srcdir/$subdir/debug/*] +set tests [prune $tests $srcdir/$subdir/gcov/*] +set tests [prune $tests $srcdir/$subdir/special/*] +set tests [prune $tests $srcdir/$subdir/tls/*] # Main loop. dg-runtest $tests "" $DEFAULT_CXXFLAGS diff --git a/gcc/testsuite/g++.dg/tls/diag-1.C b/gcc/testsuite/g++.dg/tls/diag-1.C new file mode 100644 index 0000000..697d0b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/tls/diag-1.C @@ -0,0 +1,30 @@ +/* Valid __thread specifiers. */ + +__thread int g1; +extern __thread int g2; +static __thread int g3; + +void foo() +{ + extern __thread int l1; + static __thread int l2; +} + +struct A { + static __thread int i; +}; + +__thread int A::i = 42; + +template struct B { + static __thread T t; +}; + +template +__thread T B::t = 42; + +void bar () +{ + int j = B::t; + int k = B::t; +} diff --git a/gcc/testsuite/g++.dg/tls/diag-2.C b/gcc/testsuite/g++.dg/tls/diag-2.C new file mode 100644 index 0000000..6365406 --- /dev/null +++ b/gcc/testsuite/g++.dg/tls/diag-2.C @@ -0,0 +1,25 @@ +/* Invalid __thread specifiers. */ + +__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'" } */ +typedef __thread int g4; /* { dg-error "multiple storage classes" } */ + +void foo() +{ + __thread int l1; /* { dg-error "implicitly auto and declared `__thread'" } */ + auto __thread int l2; /* { dg-error "multiple storage classes" } */ + __thread extern int l3; /* { dg-error "`__thread' before `extern'" } */ + register __thread int l4; /* { dg-error "multiple storage classes" } */ +} + +__thread void f1 (); /* { dg-error "invalid for function" } */ +extern __thread void f2 (); /* { dg-error "invalid for function" } */ +static __thread void f3 (); /* { dg-error "invalid for function" } */ +__thread void f4 () { } /* { dg-error "invalid for function" } */ + +void bar(__thread int p1); /* { dg-error "(invalid in parameter)|(specified for parameter)" } */ + +struct A { + __thread int i; /* { dg-error "specified for field" } */ +}; diff --git a/gcc/testsuite/g++.dg/tls/init-1.C b/gcc/testsuite/g++.dg/tls/init-1.C new file mode 100644 index 0000000..74f7641 --- /dev/null +++ b/gcc/testsuite/g++.dg/tls/init-1.C @@ -0,0 +1,13 @@ +/* Valid initializations. */ + +__thread int i = 42; + +static int j; +__thread int *p = &j; + +/* Note that this is valid in C++ (unlike C) as a run-time initialization. */ +int *q = &i; + +/* Valid because "const int k" is an integral constant expression in C++. */ +__thread const int k = 42; +__thread const int l = k; diff --git a/gcc/testsuite/g++.dg/tls/init-2.C b/gcc/testsuite/g++.dg/tls/init-2.C new file mode 100644 index 0000000..49df501 --- /dev/null +++ b/gcc/testsuite/g++.dg/tls/init-2.C @@ -0,0 +1,13 @@ +/* Invalid initializations. */ + +extern __thread int i; +__thread int *p = &i; /* { dg-error "run-time initialization" } */ + +extern int f(); +__thread int j = f(); /* { dg-error "run-time initialization" } */ + +struct S +{ + S(); +}; +__thread S s; /* { dg-error "run-time initialization" } */ diff --git a/gcc/testsuite/g++.dg/tls/tls.exp b/gcc/testsuite/g++.dg/tls/tls.exp new file mode 100644 index 0000000..a00dad7 --- /dev/null +++ b/gcc/testsuite/g++.dg/tls/tls.exp @@ -0,0 +1,44 @@ +# Copyright (C) 2002 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# GCC testsuite that uses the `dg.exp' driver. + +# Load support procs. +load_lib g++-dg.exp + +# Test for thread-local data supported by the platform. If it +# isn't, everything will fail with the "not supported" message. + +set comp_output [g++_target_compile \ + "$srcdir/$subdir/trivial.C" "trivial.S" assembly ""] +if { [string match "*not supported*" $comp_output] } { + return 0 +} + +# If a testcase doesn't have special options, use these. +global DEFAULT_CXXFLAGS +if ![info exists DEFAULT_CXXFLAGS] then { + set DEFAULT_CXXFLAGS " -ansi -pedantic-errors -Wno-long-long" +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.C]] "" $DEFAULT_CXXFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/g++.dg/tls/trivial.C b/gcc/testsuite/g++.dg/tls/trivial.C new file mode 100644 index 0000000..1fd7063 --- /dev/null +++ b/gcc/testsuite/g++.dg/tls/trivial.C @@ -0,0 +1 @@ +__thread int i; -- cgit v1.1