diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -1495,6 +1495,37 @@ } }; +// Specialization for ManagedStatic>. +template +class list_storage>> { + using StorageClass = ManagedStatic>; + StorageClass *Location = nullptr; // Where to store the object... + +public: + list_storage() = default; + + void clear() { + getStorageClass()->clear(); + } + + bool setLocation(Option &O, StorageClass &L) { + if (Location) + return O.error("cl::location(x) specified more than once!"); + Location = &L; + return false; + } + + template void addValue(const T &V) { + getStorageClass()->push_back(V); + } +private: + StorageClass &getStorageClass() { + assert(Location != 0 && "cl::location(...) not specified for a command " + "line option with external storage!"); + return *Location; + } +}; + // Define how to hold a class type object, such as a string. // Originally this code inherited from std::vector. In transitioning to a new // API for command line options we should change this. The new implementation diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -2542,3 +2542,45 @@ llvm::cl::ParseCommandLineOptions(argc, argv, StringRef(Overview), &llvm::nulls()); } + +// All Debug.h functionality is a no-op in NDEBUG mode. +#ifndef NDEBUG + +namespace llvm { +extern ManagedStatic> CurrentDebugType; + +extern unsigned DebugBufferSize; +} + +// -debug - Command line option to enable the DEBUG statements in the passes. +// This flag may only be enabled in debug builds. +static cl::opt Debug("debug", cl::desc("Enable debug output"), + cl::Hidden, cl::location(DebugFlag)); + +// -debug-buffer-size - Buffer the last N characters of debug output +// until program termination. +static cl::opt + DebugBufferSizeOpt("debug-buffer-size", + cl::desc("Buffer the last N characters of debug output " + "until program termination. " + "[default 0 -- immediate print-out]"), + cl::Hidden, + cl::location(llvm::DebugBufferSize)); + +static cl::list>> + DebugOnly("debug-only", + cl::desc("Enable a specific type of debug output (comma " + "separated list of types)"), + cl::Hidden, cl::ZeroOrMore, cl::value_desc("debug string"), + cl::location(llvm::CurrentDebugType), cl::CommaSeparated, + cl::callback([](const std::string &) { DebugFlag = true; })); + +#endif + +namespace llvm { +extern bool DisableSymbolicationFlag; +} + +static cl::opt DisableSymbolication( + "disable-symbolication", cl::desc("Disable symbolizing crash backtraces."), + cl::location(llvm::DisableSymbolicationFlag), cl::Hidden); diff --git a/llvm/lib/Support/Debug.cpp b/llvm/lib/Support/Debug.cpp --- a/llvm/lib/Support/Debug.cpp +++ b/llvm/lib/Support/Debug.cpp @@ -42,7 +42,7 @@ /// Exported boolean set by the -debug option. bool DebugFlag = false; -static ManagedStatic> CurrentDebugType; +ManagedStatic> CurrentDebugType; /// Return true if the specified string is the debug type /// specified on the command line, or if none was specified on the command line @@ -79,44 +79,10 @@ // All Debug.h functionality is a no-op in NDEBUG mode. #ifndef NDEBUG -// -debug - Command line option to enable the DEBUG statements in the passes. -// This flag may only be enabled in debug builds. -static cl::opt -Debug("debug", cl::desc("Enable debug output"), cl::Hidden, - cl::location(DebugFlag)); - -// -debug-buffer-size - Buffer the last N characters of debug output -//until program termination. -static cl::opt -DebugBufferSize("debug-buffer-size", - cl::desc("Buffer the last N characters of debug output " - "until program termination. " - "[default 0 -- immediate print-out]"), - cl::Hidden, - cl::init(0)); - -namespace { - -struct DebugOnlyOpt { - void operator=(const std::string &Val) const { - if (Val.empty()) - return; - DebugFlag = true; - SmallVector dbgTypes; - StringRef(Val).split(dbgTypes, ',', -1, false); - for (auto dbgType : dbgTypes) - CurrentDebugType->push_back(dbgType); - } -}; - +namespace llvm { +unsigned DebugBufferSize = 0; } -static DebugOnlyOpt DebugOnlyOptLoc; - -static cl::opt > -DebugOnly("debug-only", cl::desc("Enable a specific type of debug output (comma separated list of types)"), - cl::Hidden, cl::ZeroOrMore, cl::value_desc("debug string"), - cl::location(DebugOnlyOptLoc), cl::ValueRequired); // Signal handlers - dump debug output on termination. static void debug_user_sig_handler(void *Cookie) { // This is a bit sneaky. Since this is under #ifndef NDEBUG, we diff --git a/llvm/lib/Support/Signals.cpp b/llvm/lib/Support/Signals.cpp --- a/llvm/lib/Support/Signals.cpp +++ b/llvm/lib/Support/Signals.cpp @@ -37,12 +37,10 @@ using namespace llvm; +namespace llvm { // Use explicit storage to avoid accessing cl::opt in a signal handler. -static bool DisableSymbolicationFlag = false; -static cl::opt - DisableSymbolication("disable-symbolication", - cl::desc("Disable symbolizing crash backtraces."), - cl::location(DisableSymbolicationFlag), cl::Hidden); +bool DisableSymbolicationFlag = false; +} // Callbacks to run in signal handler must be lock-free because a signal handler // could be running as we add new callbacks. We don't add unbounded numbers of diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp --- a/llvm/unittests/Support/CommandLineTest.cpp +++ b/llvm/unittests/Support/CommandLineTest.cpp @@ -1785,6 +1785,32 @@ cl::ResetAllOptionOccurrences(); } +TEST(CommandLineTest, ManagedStaticLocation) { + cl::ResetCommandLineParser(); + + ManagedStatic> ManagedStringVec; + + StackOption OptA("a", cl::desc("option a")); + StackOption>>> + ManagedList( + "managedlist", + cl::desc("option managedlist -- This option turns on options a when " + "'foo' is included in list"), + cl::location(ManagedStringVec), cl::CommaSeparated, + cl::callback([&](const std::string &Str) { + if (Str == "foo") + OptA = true; + })); + + const char *args[] = {"prog", "--managedlist=foo"}; + EXPECT_TRUE(cl::ParseCommandLineOptions(2, args)); + EXPECT_TRUE(OptA); + EXPECT_TRUE(ManagedStringVec->size() == 1); + + cl::ResetAllOptionOccurrences(); +} + enum Enum { Val1, Val2 }; static cl::bits ExampleBits( cl::desc("An example cl::bits to ensure it compiles"),