Bug 27557 - OpenMP threadprivate directive does not work with non-POD types
Summary: OpenMP threadprivate directive does not work with non-POD types
Status: NEW
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.2.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
Keywords: openmp
: 34303 35246 (view as bug list)
Depends on: 26943
  Show dependency treegraph
Reported: 2006-05-11 14:45 UTC by Georg Baum
Modified: 2019-01-05 17:19 UTC (History)
14 users (show)

See Also:
Known to work:
Known to fail:
Last reconfirmed: 2006-05-18 16:51:18


Note You need to log in before you can comment on or make changes to this bug.
Description Georg Baum 2006-05-11 14:45:31 UTC
Compiling the fragment

struct A {
        A() {}
extern A a;
#pragma omp threadprivate(a)
A a;

with svn from yesterday yields
LANG=C g++-4.2 -fopenmp -c x.cpp -o x.o
x.cpp:6: error: 'a' cannot be thread-local because it has non-POD type 'A'
x.cpp:6: error: 'a' is thread-local and so cannot be dynamically initialized

It works if I remove the definition of a (last line).
I could not find anything in the OpenMP spec (version 2.5) stating that non-POD threadprivate variables are not allowed. If I change the above to

struct A {
        A() {}
A a;
#pragma omp threadprivate(a)

I get

LANG=C g++-4.2 -fopenmp -c x.cpp -o x.o
x.cpp:5: error: 'a' declared 'threadprivate' after first use

I believe that both variants are allowed by the OpenMP spec (version 2.5) and they compile fine with icc 8.1. The spec says something about non-POD variaables with explicit initializers in section 2.8.2 on page 69, but that does not apply here. Please correct me if I am wrong.
Comment 1 Jakub Jelinek 2006-05-16 10:20:45 UTC
Guess the message should be sorry rather than error.
Without glibc and binutils support for .tinit_array/.tfini_array this really isn't fixable.
Comment 2 Georg Baum 2006-05-16 15:04:25 UTC
Yes, I think that would be good. Then you know that you are not doing something wrong but that it is a tool chain limitation.
Comment 3 Andrew Pinski 2006-05-18 16:51:18 UTC
Comment 4 Andrew Pinski 2007-11-30 21:56:33 UTC
*** Bug 34303 has been marked as a duplicate of this bug. ***
Comment 5 Andrew Pinski 2008-02-18 05:08:36 UTC
*** Bug 35246 has been marked as a duplicate of this bug. ***
Comment 6 Brooks Moses 2011-04-06 19:54:39 UTC
It appears that this underlying issue will also affect C++0x support for thread-local storage, assuming that it also allows non-POD thread-local objects.  (See links from http://gcc.gnu.org/projects/cxx0x.html.)

This is also looking like it's going to be a significant problem for us in the near future in using OpenMP.

Are there GLIBC and binutils issues filed for the necessary underlying functionality that Jakub mentions in comment 1?  If so, what are they?  If not, what additional information is needed to file a coherent and accurate feature request there?
Comment 7 Jason Merrill 2012-10-15 20:36:16 UTC
The first fragment will be supported in GCC 4.8.
Comment 8 Carlos O'Donell 2012-11-12 18:29:12 UTC
The glibc community is aware of this issue. I've added it to our generic todo list from which developers can help coordinate an implementation.

Comment 9 Jakub Jelinek 2013-03-22 14:41:46 UTC
GCC 4.8.0 is being released, adjusting target milestone.
Comment 10 Jakub Jelinek 2013-05-31 10:57:30 UTC
GCC 4.8.1 has been released.
Comment 11 Siddhesh Poyarekar 2013-06-13 09:35:12 UTC
I had added __cxa_thread_atexit_impl to glibc earlier this year to support c++11 thread_local destructors[1][2].  Wouldn't that be good enough support from glibc for openmp too?

[1] http://sourceware.org/glibc/wiki/Destructor%20support%20for%20thread_local%20variables
[2] http://sourceware.org/git/?p=glibc.git;a=commit;h=ba384f6ed9275f3966505f2375b56d169e3dc588
Comment 12 Jakub Jelinek 2013-10-16 09:49:47 UTC
GCC 4.8.2 has been released.
Comment 13 Matthew Krafczyk 2014-01-24 16:57:47 UTC
Hi, this is still broken in the latest git version of gcc. What are the hurdles which need to be accomplished to get this bug fixed?
Comment 14 Siddhesh Poyarekar 2014-02-06 09:03:23 UTC
I spoke to Jason last week and have now confirmed that the first fragment indeed works correctly with 4.8.  Declaring a variable threadprivate *after* it is defined is not yet supported, but it should not be very difficult to work around that limitation.

I also have confirmation that the glibc support in place for threadprivate/thread_local is sufficient and complete, so I'm closing out the glibc TODO item.
Comment 15 Matthew Krafczyk 2014-02-17 00:20:53 UTC
I can now confirm what siddhesh says. with 4.8 the first fragment succeeds, while the second fails.

I also tested the git gcc and git glibc, and the first fragment succeeds, while the second fragment still fails.
Comment 16 Matthew Krafczyk 2015-03-21 22:18:12 UTC
I've just checked this bug again with ubuntu 14.10. This is with glibc 2.19, and with the master branch of gcc (commit 3c4e189973c43b7f3c2ebb27abf32e9cb175ba82).

The first fragment succeeds, but the second fragment still fails.
Comment 17 Sameer Sheorey 2016-04-17 19:15:08 UTC
The second fragment still fails in gcc 5.3.1 (OpenSuse 13.2). I noticed that the C++11 version succeeds:

struct A {
        A() {}
thread_local A a;

Is it possible to migrate this to the OpenMP implementation as well?
Comment 18 Yves Vandriessche 2018-06-18 12:32:59 UTC
As mentioned by Sameer, thread_local now works, but the threadprivate OpenMP directive still fails with a "declared 'threadprivate' after first use" error.

My test fragment, is as follows. It should only print a single "ctor" and twice the same set of distinct pointers:

#include <cstdio>
#include <omp.h>

struct Foo {
  Foo() {puts("ctor");}
  int a;

int bar() {
  int sum=0;
  // // alternative to omp threadprivate, works with gcc
  // thread_local Foo local;
#pragma omp parallel reduction(+:sum)
    static Foo local;
    #pragma omp threadprivate(local)
    local.a = omp_get_thread_num();
    printf("%p\n", &local);
    sum += local.a;
  printf("%d\n", sum);
  return sum;

int main(int argc, char** argv) {
  return 0;