[llvm] r357714 - Ensure that ManagedStatic is constant initialized in MSVC 2017 & 2019

Reid Kleckner via llvm-commits llvm-commits at lists.llvm.org
Thu Apr 4 11:30:07 PDT 2019


Author: rnk
Date: Thu Apr  4 11:30:07 2019
New Revision: 357714

URL: http://llvm.org/viewvc/llvm-project?rev=357714&view=rev
Log:
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<void*>.

Modified:
    llvm/trunk/include/llvm/Support/Compiler.h
    llvm/trunk/include/llvm/Support/ManagedStatic.h
    llvm/trunk/lib/Support/CommandLine.cpp

Modified: llvm/trunk/include/llvm/Support/Compiler.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Compiler.h?rev=357714&r1=357713&r2=357714&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/Compiler.h (original)
+++ llvm/trunk/include/llvm/Support/Compiler.h Thu Apr  4 11:30:07 2019
@@ -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__

Modified: llvm/trunk/include/llvm/Support/ManagedStatic.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/ManagedStatic.h?rev=357714&r1=357713&r2=357714&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/ManagedStatic.h (original)
+++ llvm/trunk/include/llvm/Support/ManagedStatic.h Thu Apr  4 11:30:07 2019
@@ -32,18 +32,37 @@ template <typename T, size_t N> struct o
   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<void *> 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<void *> 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; }
 

Modified: llvm/trunk/lib/Support/CommandLine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/CommandLine.cpp?rev=357714&r1=357713&r2=357714&view=diff
==============================================================================
--- llvm/trunk/lib/Support/CommandLine.cpp (original)
+++ llvm/trunk/lib/Support/CommandLine.cpp Thu Apr  4 11:30:07 2019
@@ -373,11 +373,16 @@ void OptionCategory::registerCategory()
   GlobalParser->registerCategory(this);
 }
 
-// A special subcommand representing no subcommand
-ManagedStatic<SubCommand> 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<SubCommand>
+    llvm::cl::TopLevelSubCommand;
 
 // A special subcommand that can be used to put an option into all subcommands.
-ManagedStatic<SubCommand> llvm::cl::AllSubCommands;
+LLVM_REQUIRE_CONSTANT_INITIALIZATION ManagedStatic<SubCommand>
+    llvm::cl::AllSubCommands;
 
 void SubCommand::registerSubCommand() {
   GlobalParser->registerSubCommand(this);




More information about the llvm-commits mailing list