llvm-project icon indicating copy to clipboard operation
llvm-project copied to clipboard

static __thread T* ptr(0); error: initializer for thread-local variable must be a constant expression (while T* ptr = 0 will work)

Open llvmbot opened this issue 11 years ago • 4 comments

Bugzilla Link 21690
Version trunk
OS Linux
Reporter LLVM Bugzilla Contributor
CC @hfinkel

Extended Description

I bumped Clang to pre-3.6 (65d8b4c4998b3a0c20934ea72ede72ef4838a004, r222081, ~15 Nov). Have not checked the trunk version.

$ cat test.cc
template <typename T>
void dummy() {
 static __thread T* ptr(0);
}
$ clang++ -std=c++11 test.cc
test.cc:3:25: error: initializer for thread-local variable must be a constant expression
 static __thread T* ptr(0);
                       ^~~
test.cc:3:22: note: use 'thread_local' to allow this
 static __thread T* ptr(0);
                    ^
1 error generated.

The following will work:

static __thread T* ptr;
static __thread T* ptr = 0;
static __thread T* ptr = nullptr;
static thread_local T* ptr(nullptr);

The following will not work:

static __thread T* ptr{0};
static __thread T* ptr(0);

It works with c-like initialization, but not with constructor initialization or uniform initialization.

We are assigning initial value of pointer (nullptr), isn't nullptr/0 are constant expression here?

llvmbot avatar Nov 29 '14 16:11 llvmbot

Reconfirmed on trunk with following:

template <typename T>
void dummy() {
 static __thread T* ptr(0);
}

efriedma-quic avatar Jun 27 '23 03:06 efriedma-quic

I am looking at where this diagnostic is generated:

    if (var->getType().isDestructedType()) {
      // GNU C++98 edits for __thread, [basic.start.term]p3:
      //   The type of an object with thread storage duration shall not
      //   have a non-trivial destructor.
      Diag(var->getLocation(), diag::err_thread_nontrivial_dtor);
      if (getLangOpts().CPlusPlus11)
        Diag(var->getLocation(), diag::note_use_thread_local);
    } else if (getLangOpts().CPlusPlus && var->hasInit()) {
      if (!checkConstInit()) {
        // GNU C++98 edits for __thread, [basic.start.init]p4:
        //   An object of thread storage duration shall not require dynamic
        //   initialization.
        // FIXME: Need strict checking here.
        Diag(CacheCulprit->getExprLoc(), diag::err_thread_dynamic_init)
          << CacheCulprit->getSourceRange();
        if (getLangOpts().CPlusPlus11)
          Diag(var->getLocation(), diag::note_use_thread_local);
      }
    }

and I think this looks like a bug but I would have do more digging.

CC @zygoloid

shafik avatar Jun 27 '23 15:06 shafik

We shouldn't be trying to check if a dependent variable/initializer is constant.

Whether this check makes sense at all is a separate issue.

efriedma-quic avatar Jun 27 '23 17:06 efriedma-quic

The other calls to checkConstInit are guarded by:

  if (getLangOpts().CPlusPlus && !type->isDependentType() && Init &&
      !Init->isValueDependent() &&

... some of which seem to be missing here. The isDestructedType check for __thread also should be skipped for a variable with a dependent type, but we seem to get away with that because we seem to treat dependent types as trivially-destructed.

zygoloid avatar Jun 27 '23 20:06 zygoloid