Follow-up for r167411 to un-break ASan on Mac. Move SanitizerArgs to a header file and use it on Darwin toolchain.

llvm-svn: 167460
diff --git a/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp
index 973df10..2eca3fe 100644
--- a/clang/lib/Driver/Tools.cpp
+++ b/clang/lib/Driver/Tools.cpp
@@ -33,6 +33,7 @@
 #include "llvm/Support/ErrorHandling.h"
 
 #include "InputInfo.h"
+#include "SanitizerArgs.h"
 #include "ToolChains.h"
 
 using namespace clang::driver;
@@ -1452,128 +1453,44 @@
     RelaxDefault);
 }
 
-namespace {
-struct SanitizerArgs {
-  /// Assign ordinals to sanitizer flags. We'll use the ordinal values as
-  /// bit positions within \c Kind.
-  enum SanitizeOrdinal {
-#define SANITIZER(NAME, ID) SO_##ID,
-#include "clang/Basic/Sanitizers.def"
-    SO_Count
-  };
-
-  /// Bugs to catch at runtime.
-  enum SanitizeKind {
-#define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
-#define SANITIZER_GROUP(NAME, ID, ALIAS) ID = ALIAS,
-#include "clang/Basic/Sanitizers.def"
-
-    NeedsAsanRt = Address,
-    NeedsTsanRt = Thread,
-    NeedsUbsanRt = Undefined
-  };
-  unsigned Kind;
-
-  SanitizerArgs() : Kind(0) {}
-
-  bool needsAsanRt() const { return Kind & NeedsAsanRt; }
-  bool needsTsanRt() const { return Kind & NeedsTsanRt; }
-  bool needsUbsanRt() const { return Kind & NeedsUbsanRt; }
-
-  /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
-  /// Returns a member of the \c SanitizeKind enumeration, or \c 0 if \p Value
-  /// is not known.
-  static unsigned parse(const char *Value) {
-    return llvm::StringSwitch<SanitizeKind>(Value)
-#define SANITIZER(NAME, ID) .Case(NAME, ID)
-#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID)
-#include "clang/Basic/Sanitizers.def"
-      .Default(SanitizeKind());
-  }
-
-  /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
-  /// invalid components.
-  static unsigned parse(const Driver &D, const Arg *A) {
-    unsigned Kind = 0;
-    for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
-      if (unsigned K = parse(A->getValue(I)))
-        Kind |= K;
-      else
-        D.Diag(diag::err_drv_unsupported_option_argument)
-          << A->getOption().getName() << A->getValue(I);
-    }
-    return Kind;
-  }
-
-  void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const {
-    if (!Kind)
-      return;
-    llvm::SmallString<256> SanitizeOpt("-fsanitize=");
-#define SANITIZER(NAME, ID) \
-    if (Kind & ID) \
-      SanitizeOpt += NAME ",";
-#include "clang/Basic/Sanitizers.def"
-    SanitizeOpt.pop_back();
-    CmdArgs.push_back(Args.MakeArgString(SanitizeOpt));
-  }
-};
-}
-
-/// Produce an argument string from argument \p A, which shows how it provides a
-/// value in \p Mask. For instance, the argument "-fsanitize=address,alignment"
-/// with mask \c NeedsUbsanRt would produce "-fsanitize=alignment".
-static std::string describeSanitizeArg(const ArgList &Args, const Arg *A,
-                                       unsigned Mask) {
-  if (!A->getOption().matches(options::OPT_fsanitize_EQ))
-    return A->getAsString(Args);
-
-  for (unsigned I = 0, N = A->getNumValues(); I != N; ++I)
-    if (SanitizerArgs::parse(A->getValue(I)) & Mask)
-      return std::string("-fsanitize=") + A->getValue(I);
-
-  llvm_unreachable("arg didn't provide expected value");
-}
-
-/// Parse the sanitizer arguments from an argument list.
-static SanitizerArgs getSanitizerArgs(const Driver &D, const ArgList &Args) {
-  SanitizerArgs Sanitize;
+SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) {
+  Kind = 0;
 
   const Arg *AsanArg, *TsanArg, *UbsanArg;
-
   for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) {
     unsigned Add = 0, Remove = 0;
     const char *DeprecatedReplacement = 0;
     if ((*I)->getOption().matches(options::OPT_faddress_sanitizer)) {
-      Add = SanitizerArgs::Address;
+      Add = Address;
       DeprecatedReplacement = "-fsanitize=address";
     } else if ((*I)->getOption().matches(options::OPT_fno_address_sanitizer)) {
-      Remove = SanitizerArgs::Address;
+      Remove = Address;
       DeprecatedReplacement = "-fno-sanitize=address";
     } else if ((*I)->getOption().matches(options::OPT_fthread_sanitizer)) {
-      Add = SanitizerArgs::Thread;
+      Add = Thread;
       DeprecatedReplacement = "-fsanitize=thread";
     } else if ((*I)->getOption().matches(options::OPT_fno_thread_sanitizer)) {
-      Remove = SanitizerArgs::Thread;
+      Remove = Thread;
       DeprecatedReplacement = "-fno-sanitize=thread";
     } else if ((*I)->getOption().matches(options::OPT_fcatch_undefined_behavior)) {
-      Add = SanitizerArgs::Undefined;
+      Add = Undefined;
       DeprecatedReplacement = "-fsanitize=undefined";
     } else if ((*I)->getOption().matches(options::OPT_fsanitize_EQ)) {
-      Add = SanitizerArgs::parse(D, *I);
+      Add = parse(D, *I);
     } else if ((*I)->getOption().matches(options::OPT_fno_sanitize_EQ)) {
-      Remove = SanitizerArgs::parse(D, *I);
+      Remove = parse(D, *I);
     } else {
       continue;
     }
 
     (*I)->claim();
 
-    Sanitize.Kind |= Add;
-    Sanitize.Kind &= ~Remove;
+    Kind |= Add;
+    Kind &= ~Remove;
 
-    if (Add & SanitizerArgs::NeedsAsanRt) AsanArg = *I;
-    if (Add & SanitizerArgs::NeedsTsanRt) TsanArg = *I;
-    if (Add & SanitizerArgs::NeedsUbsanRt) UbsanArg = *I;
+    if (Add & NeedsAsanRt) AsanArg = *I;
+    if (Add & NeedsTsanRt) TsanArg = *I;
+    if (Add & NeedsUbsanRt) UbsanArg = *I;
 
     // If this is a deprecated synonym, produce a warning directing users
     // towards the new spelling.
@@ -1584,19 +1501,15 @@
 
   // Only one runtime library can be used at once.
   // FIXME: Allow Ubsan to be combined with the other two.
-  bool NeedsAsan = Sanitize.needsAsanRt();
-  bool NeedsTsan = Sanitize.needsTsanRt();
-  bool NeedsUbsan = Sanitize.needsUbsanRt();
+  bool NeedsAsan = needsAsanRt();
+  bool NeedsTsan = needsTsanRt();
+  bool NeedsUbsan = needsUbsanRt();
   if (NeedsAsan + NeedsTsan + NeedsUbsan > 1)
     D.Diag(diag::err_drv_argument_not_allowed_with)
       << describeSanitizeArg(Args, NeedsAsan ? AsanArg : TsanArg,
-                             NeedsAsan ? SanitizerArgs::NeedsAsanRt
-                                       : SanitizerArgs::NeedsTsanRt)
+                             NeedsAsan ? NeedsAsanRt : NeedsTsanRt)
       << describeSanitizeArg(Args, NeedsUbsan ? UbsanArg : TsanArg,
-                             NeedsUbsan ? SanitizerArgs::NeedsUbsanRt
-                                        : SanitizerArgs::NeedsTsanRt);
-
-  return Sanitize;
+                             NeedsUbsan ? NeedsUbsanRt : NeedsTsanRt);
 }
 
 /// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
@@ -2518,7 +2431,7 @@
   Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree);
   Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type);
 
-  SanitizerArgs Sanitize = getSanitizerArgs(D, Args);
+  SanitizerArgs Sanitize(D, Args);
   Sanitize.addArgs(Args, CmdArgs);
 
   // Report and error for -faltivec on anything other then PowerPC.
@@ -2681,7 +2594,7 @@
     CmdArgs.push_back("-fno-rtti");
 
     // -fno-rtti cannot usefully be combined with -fsanitize=vptr.
-    if (Sanitize.Kind & SanitizerArgs::Vptr) {
+    if (Sanitize.sanitizesVptr()) {
       llvm::StringRef NoRttiArg =
         Args.getLastArg(options::OPT_mkernel,
                         options::OPT_fapple_kext,
@@ -4768,11 +4681,11 @@
 
   Args.AddAllArgs(CmdArgs, options::OPT_L);
 
-  // If we're building a dynamic lib with -faddress-sanitizer, unresolved
+  SanitizerArgs Sanitize(getToolChain().getDriver(), Args);
+  // If we're building a dynamic lib with -fsanitize=address, unresolved
   // symbols may appear. Mark all of them as dynamic_lookup.
   // Linking executables is handled in lib/Driver/ToolChains.cpp.
-  if (Args.hasFlag(options::OPT_faddress_sanitizer,
-                   options::OPT_fno_address_sanitizer, false)) {
+  if (Sanitize.needsAsanRt()) {
     if (Args.hasArg(options::OPT_dynamiclib) ||
         Args.hasArg(options::OPT_bundle)) {
       CmdArgs.push_back("-undefined");
@@ -6116,7 +6029,7 @@
 
   AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
 
-  SanitizerArgs Sanitize = getSanitizerArgs(D, Args);
+  SanitizerArgs Sanitize(D, Args);
 
   // Call this before we add the C++ ABI library.
   if (Sanitize.needsUbsanRt())