[llvm-bugs] [Bug 41367] New: LLVM's ManagedStatic.h fails with VS 2019 <atomic> and clang-cl due to init-order-fiasco and constexpr confusion

via llvm-bugs llvm-bugs at lists.llvm.org
Wed Apr 3 16:27:04 PDT 2019


https://bugs.llvm.org/show_bug.cgi?id=41367

            Bug ID: 41367
           Summary: LLVM's ManagedStatic.h fails with VS 2019 <atomic> and
                    clang-cl due to init-order-fiasco and constexpr
                    confusion
           Product: clang
           Version: unspecified
          Hardware: PC
                OS: Windows NT
            Status: NEW
          Severity: enhancement
          Priority: P
         Component: C++
          Assignee: unassignedclangbugs at nondot.org
          Reporter: rnk at google.com
                CC: billy.oneal at gmail.com, blitzrakete at gmail.com,
                    dgregor at apple.com, erik.pilkington at gmail.com,
                    llvm-bugs at lists.llvm.org, richard-llvm at metafoo.co.uk,
                    sfinae at hotmail.com

I installed VS 2019 and tried to self-host clang with the new headers, but it
didn't work. The symptom was this:

[1 processes, 17/531 @ 3.4/s : 4.984s ] Building AttributesCompatFunc.inc...
FAILED: lib/IR/AttributesCompatFunc.inc
cmd.exe /C "cd /D C:\src\llvm-project\build &&
C:\src\llvm-project\build\bin\llvm-tblgen.exe -gen-attrs -I
C:/src/llvm-project/llvm/lib/IR -I C:/src/llvm-project/llvm/include
C:/src/llvm-project/llvm/lib/IR/AttributesCompatFunc.td -o
lib/IR/AttributesCompatFunc.inc -d lib/IR/AttributesCompatFunc.inc.d"
llvm-tblgen.exe: Unknown command line argument '-gen-attrs'.  Try:
'C:\src\llvm-project\build\bin\llvm-tblgen.exe -help'
llvm-tblgen.exe: Did you mean '-stats'?
ninja: build stopped: subcommand failed.

The issue here is that command line options aren't being registered. This is
because TopLevelSubCommand is a ManagedStatic<SubCommand>. What happens is that
the cl::opt initializers run first, then ManagedStatic is incorrectly *not*
linker initialized, we run the ManagedStatic ctor, and we zero out the pointer
to the previously constructed list of command line flags.

The issue is that ManagedStaticBase wants to be linker initialized, but the way
it achieves that is by not having a constructor at all. It has members that
look like this:

class ManagedStaticBase {
protected:
  // This should only be used as a static variable, which guarantees that this
  // will be zero initialized.
  mutable std::atomic<void *> Ptr;
  mutable void (*DeleterFn)(void*);
  mutable const ManagedStaticBase *Next;

With clang-cl, for some reason the default constructor for this class isn't
considered to be constexpr. When I try to explicitly make it constexpr, clang
complains:
C:\src\llvm-project\llvm\include\llvm/Support/ManagedStatic.h(47,3): error:
defaulted definition of default constructor is not constexpr
  constexpr ManagedStaticBase() = default;
  ^
1 error generated.

So, clang thinks the defaulted one won't be constexpr, but it doesn't say why.
Even if it's correct, it should probably point the user at the uninitialized
members. If I initialize the members explicitly like this:

  mutable std::atomic<void *> Ptr{nullptr};
  mutable void (*DeleterFn)(void*) = nullptr;
  mutable const ManagedStaticBase *Next = nullptr;

Then the defaulted default ctor becomes constexpr and everything works as
expected.

The atomic headers have some interesting ifdefs that seem to allude to this
issue:

struct _Atomic_base : _Atomic_impl<_Bytes> {
  ...
#ifdef __clang__ // TRANSITION, VSO#406237
    constexpr _Atomic_base()
_NOEXCEPT_COND(is_nothrow_default_constructible_v<_Ty>) : _My_val() {}
#else // ^^^ no workaround ^^^ // vvv workaround vvv
    _Atomic_base() = default;
#endif // VSO#406237

The odd thing is that if this constexpr default ctor didn't exist, we might be
in business? Hard to say.

Another way of looking at this bug, if it's a clang bug, is, why is the
following an error?

struct atomic_ptr {
  constexpr atomic_ptr() = default;
  void *Ptr = nullptr;
};
struct Foo {
  atomic_ptr Ptr;
  int y;
  constexpr Foo() = default; // why an error?
};
extern Foo obj;
Foo obj;

Just because 'y' has no initializer, Foo can't be constexpr, even if I ask for
it to be?

In the end, I *think* this is a clang bug, but it might be an STL bug, so I
added Billy and STL.

Anyway, there's an obvious workaround, which is to add a real constexpr
constructor to ManagedStatic, assuming that works with all the toolchains we
support. I'm going to try that.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20190403/ebe14fa6/attachment.html>


More information about the llvm-bugs mailing list