Skip to content

Commit c06a470

Browse files
committed
Try once more to ensure constant initializaton of ManagedStatics
First, use the old style of linker initialization for MSVC 2019 in addition to 2017. MSVC 2019 emits a dynamic initializer for ManagedStatic when compiled in debug mode, and according to zturner, also sometimes in release mode. I wasn't able to reproduce that, but it seems best to stick with the old code that works. When clang is using the MSVC STL, we have to give ManagedStatic a constexpr constructor that fully zero initializes all fields, otherwise it emits a dynamic initializer. The MSVC STL implementation of std::atomic has a non-trivial (but constexpr) default constructor that zero initializes the atomic value. Because one of the fields has a non-trivial constructor, ManagedStatic ends up with a non-trivial ctor. The ctor is not constexpr, so clang ends up emitting a dynamic initializer, even though it simply does zero initialization. To make it constexpr, we must initialize all fields of the ManagedStatic. However, while the constructor that takes a pointer is marked constexpr, clang says it does not evaluate to a constant because it contains a cast from a pointer to an integer. I filed this as: https://developercommunity.visualstudio.com/content/problem/545566/stdatomic-value-constructor-is-not-actually-conste.html Once we do that, we can add back the LLVM_REQUIRE_CONSTANT_INITIALIZATION marker, and so far as I'm aware it compiles successfully on all supported targets. llvm-svn: 359135
1 parent 65a422c commit c06a470

File tree

2 files changed

+15
-10
lines changed

2 files changed

+15
-10
lines changed

llvm/include/llvm/Support/ManagedStatic.h

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,20 +32,24 @@ template <typename T, size_t N> struct object_deleter<T[N]> {
3232
static void call(void *Ptr) { delete[](T *)Ptr; }
3333
};
3434

35-
// If the current compiler is MSVC 2017 or earlier, then we have to work around
36-
// a bug where MSVC emits code to perform dynamic initialization even if the
37-
// class has a constexpr constructor. Instead, fall back to the C++98 strategy
38-
// where there are no constructors or member initializers. We can remove this
39-
// when MSVC 2019 (19.20+) is our minimum supported version.
40-
#if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1920
41-
#define LLVM_AVOID_CONSTEXPR_CTOR
35+
// ManagedStatic must be initialized to zero, and it must *not* have a dynamic
36+
// initializer because managed statics are often created while running other
37+
// dynamic initializers. In standard C++11, the best way to accomplish this is
38+
// with a constexpr default constructor. However, different versions of the
39+
// Visual C++ compiler have had bugs where, even though the constructor may be
40+
// constexpr, a dynamic initializer may be emitted depending on optimization
41+
// settings. For the affected versions of MSVC, use the old linker
42+
// initialization pattern of not providing a constructor and leaving the fields
43+
// uninitialized.
44+
#if !defined(_MSC_VER) || defined(__clang__)
45+
#define LLVM_USE_CONSTEXPR_CTOR
4246
#endif
4347

4448
/// ManagedStaticBase - Common base class for ManagedStatic instances.
4549
class ManagedStaticBase {
4650
protected:
47-
#ifndef LLVM_AVOID_CONSTEXPR_CTOR
48-
mutable std::atomic<void *> Ptr{nullptr};
51+
#ifdef LLVM_USE_CONSTEXPR_CTOR
52+
mutable std::atomic<void *> Ptr{};
4953
mutable void (*DeleterFn)(void *) = nullptr;
5054
mutable const ManagedStaticBase *Next = nullptr;
5155
#else
@@ -59,7 +63,7 @@ class ManagedStaticBase {
5963
void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const;
6064

6165
public:
62-
#ifndef LLVM_AVOID_CONSTEXPR_CTOR
66+
#ifdef LLVM_USE_CONSTEXPR_CTOR
6367
constexpr ManagedStaticBase() = default;
6468
#endif
6569

llvm/lib/Support/CommandLine.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,7 @@ void OptionCategory::registerCategory() {
412412
// that this ManagedStatic uses constant initailization and not dynamic
413413
// initialization because it is referenced from cl::opt constructors, which run
414414
// dynamically in an arbitrary order.
415+
LLVM_REQUIRE_CONSTANT_INITIALIZATION
415416
ManagedStatic<SubCommand> llvm::cl::TopLevelSubCommand;
416417

417418
// A special subcommand that can be used to put an option into all subcommands.

0 commit comments

Comments
 (0)