diff options
-rw-r--r-- | gcc/c/c-decl.cc | 20 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/c2x-thread-local-2.c | 40 |
2 files changed, 57 insertions, 3 deletions
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc index 945e45b..b5b491c 100644 --- a/gcc/c/c-decl.cc +++ b/gcc/c/c-decl.cc @@ -2442,8 +2442,20 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl, return false; } - /* Multiple initialized definitions are not allowed (6.9p3,5). */ - if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl)) + /* Multiple initialized definitions are not allowed (6.9p3,5). + For this purpose, C2x makes it clear that thread-local + declarations without extern are definitions, not tentative + definitions, whether or not they have initializers. The + wording before C2x was unclear; literally it would have made + uninitialized thread-local declarations into tentative + definitions only if they also used static, but without saying + explicitly whether or not other cases count as + definitions at all. */ + if ((DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl)) + || (flag_isoc2x + && DECL_THREAD_LOCAL_P (newdecl) + && !DECL_EXTERNAL (newdecl) + && !DECL_EXTERNAL (olddecl))) { auto_diagnostic_group d; error ("redefinition of %q+D", newdecl); @@ -5714,10 +5726,12 @@ finish_decl (tree decl, location_t init_loc, tree init, /* A static variable with an incomplete type is an error if it is initialized. Also if it is not file scope. + Also if it is thread-local (in C2x). Otherwise, let it through, but if it is not `extern' then it may cause an error message later. */ ? (DECL_INITIAL (decl) != NULL_TREE - || !DECL_FILE_SCOPE_P (decl)) + || !DECL_FILE_SCOPE_P (decl) + || (flag_isoc2x && DECL_THREAD_LOCAL_P (decl))) /* An automatic variable with an incomplete type is an error. */ : !DECL_EXTERNAL (decl))) diff --git a/gcc/testsuite/gcc.dg/c2x-thread-local-2.c b/gcc/testsuite/gcc.dg/c2x-thread-local-2.c new file mode 100644 index 0000000..d199ff2 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c2x-thread-local-2.c @@ -0,0 +1,40 @@ +/* Test that thread-local declarations are not considered tentative definitions + in C2x. */ +/* { dg-do compile } */ +/* { dg-options "-std=c2x -pedantic-errors" } */ + +thread_local int a; /* { dg-message "previous" } */ +thread_local int a; /* { dg-error "redefinition" } */ + +static thread_local int b; /* { dg-message "previous" } */ +static thread_local int b; /* { dg-error "redefinition" } */ + +thread_local int c; /* { dg-message "previous" } */ +thread_local int c = 1; /* { dg-error "redefinition" } */ + +static thread_local int d; /* { dg-message "previous" } */ +static thread_local int d = 1; /* { dg-error "redefinition" } */ + +thread_local int e = 1; /* { dg-message "previous" } */ +thread_local int e; /* { dg-error "redefinition" } */ + +static thread_local int f = 1; /* { dg-message "previous" } */ +static thread_local int f; /* { dg-error "redefinition" } */ + +/* Not being a tentative definition means that incomplete arrays are an error + rather than defaulting to size 1. */ +thread_local int g[]; /* { dg-error "storage size" } */ +static thread_local int h[]; /* { dg-error "array size missing" } */ +extern thread_local int i[]; + +thread_local int j[] = { 0 }; +static thread_local int k[] = { 0 }; + +thread_local int l; +extern thread_local int l; + +extern thread_local int m; +thread_local int m; + +static thread_local int n; +extern thread_local int n; |