From: Reid Kleckner Date: Thu, 4 Apr 2019 18:30:07 +0000 (+0000) Subject: Ensure that ManagedStatic is constant initialized in MSVC 2017 & 2019 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f3a823c16205a1b36285d4a51b3a2771ea814415;p=llvm Ensure that ManagedStatic is constant initialized in MSVC 2017 & 2019 Fixes PR41367. This effectively relands r357655 with a workaround for MSVC 2017. I tried various approaches with unions, but I ended up going with this ifdef approach because it lets us write the proper C++11 code that we want to write, with a separate workaround that we can delete when we drop MSVC 2017 support. This also adds LLVM_REQUIRE_CONSTANT_INITIALIZATION, which wraps [[clang::require_constant_initialization]]. This actually detected a minor issue when using clang-cl where clang wasn't able to use the constexpr constructor in MSVC's STL, so I switched back to using the default ctor of std::atomic. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@357714 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Support/Compiler.h b/include/llvm/Support/Compiler.h index a81488a2e4c..3f4f465f396 100644 --- a/include/llvm/Support/Compiler.h +++ b/include/llvm/Support/Compiler.h @@ -254,6 +254,15 @@ #define LLVM_FALLTHROUGH #endif +/// LLVM_REQUIRE_CONSTANT_INITIALIZATION - Apply this to globals to ensure that +/// they are constant initialized. +#if __has_cpp_attribute(clang::require_constant_initialization) +#define LLVM_REQUIRE_CONSTANT_INITIALIZATION \ + [[clang::require_constant_initialization]] +#else +#define LLVM_REQUIRE_CONSTANT_INITIALIZATION +#endif + /// LLVM_EXTENSION - Support compilers where we have a keyword to suppress /// pedantic diagnostics. #ifdef __GNUC__ diff --git a/include/llvm/Support/ManagedStatic.h b/include/llvm/Support/ManagedStatic.h index 441f24e05af..0290510e030 100644 --- a/include/llvm/Support/ManagedStatic.h +++ b/include/llvm/Support/ManagedStatic.h @@ -32,18 +32,37 @@ template struct object_deleter { static void call(void *Ptr) { delete[](T *)Ptr; } }; +// If the current compiler is MSVC 2017 or earlier, then we have to work around +// a bug where MSVC emits code to perform dynamic initialization even if the +// class has a constexpr constructor. Instead, fall back to the C++98 strategy +// where there are no constructors or member initializers. We can remove this +// when MSVC 2019 (19.20+) is our minimum supported version. +#if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1920 +#define LLVM_AVOID_CONSTEXPR_CTOR +#endif + /// ManagedStaticBase - Common base class for ManagedStatic instances. class ManagedStaticBase { protected: +#ifndef LLVM_AVOID_CONSTEXPR_CTOR + mutable std::atomic Ptr; + mutable void (*DeleterFn)(void *) = nullptr; + mutable const ManagedStaticBase *Next = nullptr; +#else // This should only be used as a static variable, which guarantees that this // will be zero initialized. mutable std::atomic Ptr; - mutable void (*DeleterFn)(void*); + mutable void (*DeleterFn)(void *); mutable const ManagedStaticBase *Next; +#endif void RegisterManagedStatic(void *(*creator)(), void (*deleter)(void*)) const; public: +#ifndef LLVM_AVOID_CONSTEXPR_CTOR + constexpr ManagedStaticBase() = default; +#endif + /// isConstructed - Return true if this object has not been created yet. bool isConstructed() const { return Ptr != nullptr; } diff --git a/lib/Support/CommandLine.cpp b/lib/Support/CommandLine.cpp index c1193f90e8f..d2cfef9f42a 100644 --- a/lib/Support/CommandLine.cpp +++ b/lib/Support/CommandLine.cpp @@ -373,11 +373,16 @@ void OptionCategory::registerCategory() { GlobalParser->registerCategory(this); } -// A special subcommand representing no subcommand -ManagedStatic llvm::cl::TopLevelSubCommand; +// A special subcommand representing no subcommand. It is particularly important +// that this ManagedStatic uses constant initailization and not dynamic +// initialization because it is referenced from cl::opt constructors, which run +// dynamically in an arbitrary order. +LLVM_REQUIRE_CONSTANT_INITIALIZATION ManagedStatic + llvm::cl::TopLevelSubCommand; // A special subcommand that can be used to put an option into all subcommands. -ManagedStatic llvm::cl::AllSubCommands; +LLVM_REQUIRE_CONSTANT_INITIALIZATION ManagedStatic + llvm::cl::AllSubCommands; void SubCommand::registerSubCommand() { GlobalParser->registerSubCommand(this);