summaryrefslogtreecommitdiffstats
path: root/llvm
diff options
context:
space:
mode:
authorReid Kleckner <rnk@google.com>2019-04-04 18:30:07 +0000
committerReid Kleckner <rnk@google.com>2019-04-04 18:30:07 +0000
commit41fe3a54c2613d81a68eb02ae76b394d0b8849ab (patch)
treec3f88d5e27f194a2251e0243dce6e9bf285e5cd8 /llvm
parent1ee8876d3d703389a27f5e357f67ce1062381e05 (diff)
downloadbcm5719-llvm-41fe3a54c2613d81a68eb02ae76b394d0b8849ab.tar.gz
bcm5719-llvm-41fe3a54c2613d81a68eb02ae76b394d0b8849ab.zip
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*>. llvm-svn: 357714
Diffstat (limited to 'llvm')
-rw-r--r--llvm/include/llvm/Support/Compiler.h9
-rw-r--r--llvm/include/llvm/Support/ManagedStatic.h21
-rw-r--r--llvm/lib/Support/CommandLine.cpp11
3 files changed, 37 insertions, 4 deletions
diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h
index a81488a2e4c..3f4f465f396 100644
--- a/llvm/include/llvm/Support/Compiler.h
+++ b/llvm/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/llvm/include/llvm/Support/ManagedStatic.h b/llvm/include/llvm/Support/ManagedStatic.h
index 441f24e05af..0290510e030 100644
--- a/llvm/include/llvm/Support/ManagedStatic.h
+++ b/llvm/include/llvm/Support/ManagedStatic.h
@@ -32,18 +32,37 @@ template <typename T, size_t N> struct object_deleter<T[N]> {
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; }
diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp
index c1193f90e8f..d2cfef9f42a 100644
--- a/llvm/lib/Support/CommandLine.cpp
+++ b/llvm/lib/Support/CommandLine.cpp
@@ -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);
OpenPOWER on IntegriCloud