r221968 - [Sanitizer] Refactor SanitizerArgs parsing in Driver.

Alexey Samsonov vonosmas at gmail.com
Thu Nov 13 18:59:21 PST 2014


Author: samsonov
Date: Thu Nov 13 20:59:20 2014
New Revision: 221968

URL: http://llvm.org/viewvc/llvm-project?rev=221968&view=rev
Log:
[Sanitizer] Refactor SanitizerArgs parsing in Driver.

Remove flag parsing details from the public header.
Use SanitizerSet to represent the set of enabled sanitizers.
Cleanup the implementation: update the comments to
reflect reality, remove dead code.

No functionality change.

Modified:
    cfe/trunk/include/clang/Basic/Sanitizers.h
    cfe/trunk/include/clang/Driver/SanitizerArgs.h
    cfe/trunk/lib/Basic/Sanitizers.cpp
    cfe/trunk/lib/Driver/SanitizerArgs.cpp

Modified: cfe/trunk/include/clang/Basic/Sanitizers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Sanitizers.h?rev=221968&r1=221967&r2=221968&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Sanitizers.h (original)
+++ cfe/trunk/include/clang/Basic/Sanitizers.h Thu Nov 13 20:59:20 2014
@@ -37,6 +37,9 @@ public:
 
   /// \brief Disable all sanitizers.
   void clear();
+
+  /// \brief Returns true if at least one sanitizer is enabled.
+  bool empty() const;
 };
 
 }  // end namespace clang

Modified: cfe/trunk/include/clang/Driver/SanitizerArgs.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/SanitizerArgs.h?rev=221968&r1=221967&r2=221968&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/SanitizerArgs.h (original)
+++ cfe/trunk/include/clang/Driver/SanitizerArgs.h Thu Nov 13 20:59:20 2014
@@ -9,6 +9,7 @@
 #ifndef LLVM_CLANG_DRIVER_SANITIZERARGS_H
 #define LLVM_CLANG_DRIVER_SANITIZERARGS_H
 
+#include "clang/Basic/Sanitizers.h"
 #include "llvm/Option/Arg.h"
 #include "llvm/Option/ArgList.h"
 #include <string>
@@ -20,33 +21,7 @@ class Driver;
 class ToolChain;
 
 class 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,
-#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
-#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, ID##Group = 1 << SO_##ID##Group,
-#include "clang/Basic/Sanitizers.def"
-    NeedsAsanRt = Address,
-    NeedsTsanRt = Thread,
-    NeedsMsanRt = Memory,
-    NeedsDfsanRt = DataFlow,
-    NeedsLeakDetection = Leak,
-    NeedsUbsanRt = Undefined | Integer,
-    NotAllowedWithTrap = Vptr,
-    HasZeroBaseShadow = Thread | Memory | DataFlow,
-    NeedsUnwindTables = Address | Thread | Memory | DataFlow
-  };
-  unsigned Kind;
-
+  SanitizerSet Sanitizers;
   std::string BlacklistFile;
   int SanitizeCoverage;
   int MsanTrackOrigins;
@@ -60,90 +35,27 @@ class SanitizerArgs {
   /// Parses the sanitizer arguments from an argument list.
   SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args);
 
-  bool needsAsanRt() const { return Kind & NeedsAsanRt; }
+  bool needsAsanRt() const { return Sanitizers.has(SanitizerKind::Address); }
   bool needsSharedAsanRt() const { return AsanSharedRuntime; }
-  bool needsTsanRt() const { return Kind & NeedsTsanRt; }
-  bool needsMsanRt() const { return Kind & NeedsMsanRt; }
-  bool needsLeakDetection() const { return Kind & NeedsLeakDetection; }
+  bool needsTsanRt() const { return Sanitizers.has(SanitizerKind::Thread); }
+  bool needsMsanRt() const { return Sanitizers.has(SanitizerKind::Memory); }
   bool needsLsanRt() const {
-    return needsLeakDetection() && !needsAsanRt();
-  }
-  bool needsUbsanRt() const {
-    return !UbsanTrapOnError && (Kind & NeedsUbsanRt);
+    return Sanitizers.has(SanitizerKind::Leak) &&
+           !Sanitizers.has(SanitizerKind::Address);
   }
-  bool needsDfsanRt() const { return Kind & NeedsDfsanRt; }
+  bool needsUbsanRt() const;
+  bool needsDfsanRt() const { return Sanitizers.has(SanitizerKind::DataFlow); }
 
-  bool sanitizesVptr() const { return Kind & Vptr; }
-  bool notAllowedWithTrap() const { return Kind & NotAllowedWithTrap; }
-  bool hasZeroBaseShadow() const {
-    return (Kind & HasZeroBaseShadow) || AsanZeroBaseShadow;
-  }
-  bool needsUnwindTables() const { return Kind & NeedsUnwindTables; }
+  bool sanitizesVptr() const { return Sanitizers.has(SanitizerKind::Vptr); }
+  bool hasZeroBaseShadow() const;
+  bool needsUnwindTables() const;
   bool linkCXXRuntimes() const { return LinkCXXRuntimes; }
   void addArgs(const llvm::opt::ArgList &Args,
                llvm::opt::ArgStringList &CmdArgs) const;
 
  private:
   void clear();
-
   bool getDefaultBlacklist(const Driver &D, std::string &BLPath);
-
-  /// Parse a single value from a -fsanitize= or -fno-sanitize= value list.
-  /// Returns OR of members of the \c SanitizeKind enumeration, or \c 0
-  /// if \p Value is not known.
-  static unsigned parse(const char *Value);
-
-  /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
-  /// invalid components.
-  static unsigned parse(const Driver &D, const llvm::opt::Arg *A,
-                        bool DiagnoseErrors);
-
-  /// Parse a single flag of the form -f[no]sanitize=, or
-  /// -f*-sanitizer. Sets the masks defining required change of Kind value.
-  /// Returns true if the flag was parsed successfully.
-  static bool parse(const Driver &D, const llvm::opt::ArgList &Args,
-                    const llvm::opt::Arg *A, unsigned &Add, unsigned &Remove,
-                    bool DiagnoseErrors);
-
-  /// Produce an argument string from ArgList \p Args, which shows how it
-  /// provides a sanitizer kind in \p Mask. For example, the argument list
-  /// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
-  /// would produce "-fsanitize=vptr".
-  static std::string lastArgumentForKind(const Driver &D,
-                                         const llvm::opt::ArgList &Args,
-                                         unsigned Kind);
-
-  /// 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 llvm::opt::ArgList &Args,
-                                         const llvm::opt::Arg *A,
-                                         unsigned Mask);
-
-  /// Return the smallest superset of sanitizer set \p Kinds such that each
-  /// member of each group whose flag is set in \p Kinds has its flag set in the
-  /// result.
-  static unsigned expandGroups(unsigned Kinds);
-
-  /// Return the subset of \p Kinds supported by toolchain \p TC.  If
-  /// \p DiagnoseErrors is true, produce an error diagnostic for each sanitizer
-  /// removed from \p Kinds.
-  static unsigned filterUnsupportedKinds(const ToolChain &TC, unsigned Kinds,
-                                         const llvm::opt::ArgList &Args,
-                                         const llvm::opt::Arg *A,
-                                         bool DiagnoseErrors,
-                                         unsigned &DiagnosedKinds);
-
-  /// The flags in \p Mask are unsupported by \p TC.  If present in \p Kinds,
-  /// remove them and produce an error diagnostic referring to \p A if
-  /// \p DiagnoseErrors is true.
-  static void filterUnsupportedMask(const ToolChain &TC, unsigned &Kinds,
-                                    unsigned Mask,
-                                    const llvm::opt::ArgList &Args,
-                                    const llvm::opt::Arg *A,
-                                    bool DiagnoseErrors,
-                                    unsigned &DiagnosedKinds);
 };
 
 }  // namespace driver

Modified: cfe/trunk/lib/Basic/Sanitizers.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/Sanitizers.cpp?rev=221968&r1=221967&r2=221968&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/Sanitizers.cpp (original)
+++ cfe/trunk/lib/Basic/Sanitizers.cpp Thu Nov 13 20:59:20 2014
@@ -29,3 +29,7 @@ void SanitizerSet::set(SanitizerKind K,
 void SanitizerSet::clear() {
   Kinds = 0;
 }
+
+bool SanitizerSet::empty() const {
+  return Kinds == 0;
+}

Modified: cfe/trunk/lib/Driver/SanitizerArgs.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/SanitizerArgs.cpp?rev=221968&r1=221967&r2=221968&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/SanitizerArgs.cpp (original)
+++ cfe/trunk/lib/Driver/SanitizerArgs.cpp Thu Nov 13 20:59:20 2014
@@ -21,8 +21,120 @@
 using namespace clang::driver;
 using namespace llvm::opt;
 
+namespace {
+/// Assign ordinals to possible values of -fsanitize= flag.
+/// We use the ordinal values as bit positions within \c SanitizeKind.
+enum SanitizeOrdinal {
+#define SANITIZER(NAME, ID) SO_##ID,
+#define SANITIZER_GROUP(NAME, ID, ALIAS) SO_##ID##Group,
+#include "clang/Basic/Sanitizers.def"
+  SO_Count
+};
+
+/// Represents a set of sanitizer kinds. It is also used to define:
+/// 1) set of sanitizers each sanitizer group expands into.
+/// 2) set of sanitizers sharing a specific property (e.g.
+///    all sanitizers with zero-base shadow).
+enum SanitizeKind {
+#define SANITIZER(NAME, ID) ID = 1 << SO_##ID,
+#define SANITIZER_GROUP(NAME, ID, ALIAS)                                       \
+ID = ALIAS, ID##Group = 1 << SO_##ID##Group,
+#include "clang/Basic/Sanitizers.def"
+  NeedsUbsanRt = Undefined | Integer,
+  NotAllowedWithTrap = Vptr,
+  HasZeroBaseShadow = Thread | Memory | DataFlow,
+  NeedsUnwindTables = Address | Thread | Memory | DataFlow
+};
+}
+
+/// Returns true if set of \p Sanitizers contain at least one sanitizer from
+/// \p Kinds.
+static bool hasOneOf(const clang::SanitizerSet &Sanitizers, unsigned Kinds) {
+#define SANITIZER(NAME, ID)                                                    \
+  if (Sanitizers.has(clang::SanitizerKind::ID) && (Kinds & ID))                \
+    return true;
+#include "clang/Basic/Sanitizers.def"
+  return false;
+}
+
+/// Adds all sanitizers from \p Kinds to \p Sanitizers.
+static void addAllOf(clang::SanitizerSet &Sanitizers, unsigned Kinds) {
+#define SANITIZER(NAME, ID) \
+  if (Kinds & ID) \
+    Sanitizers.set(clang::SanitizerKind::ID, true);
+#include "clang/Basic/Sanitizers.def"
+}
+
+static unsigned toSanitizeKind(clang::SanitizerKind K) {
+#define SANITIZER(NAME, ID) \
+  if (K == clang::SanitizerKind::ID) \
+    return ID;
+#include "clang/Basic/Sanitizers.def"
+  llvm_unreachable("Invalid SanitizerKind!");
+}
+
+/// 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 parseValue(const char *Value);
+
+/// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any
+/// invalid components. Returns OR of members of \c SanitizeKind enumeration.
+static unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A,
+                               bool DiagnoseErrors);
+
+/// Parse a single flag of the form -f[no]sanitize=.
+/// Sets the masks defining required change of the set of sanitizers.
+/// Returns true if the flag was parsed successfully.
+static bool parseArgument(const Driver &D, const llvm::opt::Arg *A,
+                          unsigned &Add, unsigned &Remove, bool DiagnoseErrors);
+
+/// Produce an argument string from ArgList \p Args, which shows how it
+/// provides some sanitizer kind from \p Mask. For example, the argument list
+/// "-fsanitize=thread,vptr -fsanitize=address" with mask \c NeedsUbsanRt
+/// would produce "-fsanitize=vptr".
+static std::string lastArgumentForMask(const Driver &D,
+                                       const llvm::opt::ArgList &Args,
+                                       unsigned Mask);
+
+static std::string lastArgumentForKind(const Driver &D,
+                                       const llvm::opt::ArgList &Args,
+                                       clang::SanitizerKind K) {
+  return lastArgumentForMask(D, Args, toSanitizeKind(K));
+}
+
+/// 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 llvm::opt::Arg *A, unsigned Mask);
+
+/// For each sanitizer group bit set in \p Kinds, set the bits for sanitizers
+/// this group enables.
+static unsigned expandGroups(unsigned Kinds);
+
+/// Return the subset of \p Kinds supported by toolchain \p TC.  If
+/// \p DiagnoseErrors is true, produce an error diagnostic for each sanitizer
+/// removed from \p Kinds.
+static unsigned filterUnsupportedKinds(const ToolChain &TC, unsigned Kinds,
+                                       const llvm::opt::Arg *A,
+                                       bool DiagnoseErrors,
+                                       unsigned &DiagnosedKinds);
+
+bool SanitizerArgs::needsUbsanRt() const {
+  return !UbsanTrapOnError && hasOneOf(Sanitizers, NeedsUbsanRt);
+}
+
+bool SanitizerArgs::hasZeroBaseShadow() const {
+  return AsanZeroBaseShadow || hasOneOf(Sanitizers, HasZeroBaseShadow);
+}
+
+bool SanitizerArgs::needsUnwindTables() const {
+  return hasOneOf(Sanitizers, NeedsUnwindTables);
+}
+
 void SanitizerArgs::clear() {
-  Kind = 0;
+  Sanitizers.clear();
   BlacklistFile = "";
   SanitizeCoverage = 0;
   MsanTrackOrigins = 0;
@@ -45,7 +157,7 @@ SanitizerArgs::SanitizerArgs(const ToolC
   for (ArgList::const_reverse_iterator I = Args.rbegin(), E = Args.rend();
        I != E; ++I) {
     unsigned Add, Remove;
-    if (!parse(D, Args, *I, Add, Remove, true))
+    if (!parseArgument(D, *I, Add, Remove, true))
       continue;
     (*I)->claim();
 
@@ -55,17 +167,17 @@ SanitizerArgs::SanitizerArgs(const ToolC
     Add &= ~AllRemove;
     // At this point we have not expanded groups, so any unsupported sanitizers
     // in Add are those which have been explicitly enabled. Diagnose them.
-    Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/true,
+    Add = filterUnsupportedKinds(TC, Add, *I, /*DiagnoseErrors=*/true,
                                  DiagnosedKinds);
     Add = expandGroups(Add);
     // Group expansion may have enabled a sanitizer which is disabled later.
     Add &= ~AllRemove;
     // Silently discard any unsupported sanitizers implicitly enabled through
     // group expansion.
-    Add = filterUnsupportedKinds(TC, Add, Args, *I, /*DiagnoseErrors=*/false,
+    Add = filterUnsupportedKinds(TC, Add, *I, /*DiagnoseErrors=*/false,
                                  DiagnosedKinds);
 
-    Kind |= Add;
+    addAllOf(Sanitizers, Add);
   }
 
   UbsanTrapOnError =
@@ -73,37 +185,37 @@ SanitizerArgs::SanitizerArgs(const ToolC
                  options::OPT_fno_sanitize_undefined_trap_on_error, false);
 
   // Warn about undefined sanitizer options that require runtime support.
-  if (UbsanTrapOnError && notAllowedWithTrap()) {
-    D.Diag(diag::err_drv_argument_not_allowed_with)
-      << lastArgumentForKind(D, Args, NotAllowedWithTrap)
+  if (UbsanTrapOnError && hasOneOf(Sanitizers, NotAllowedWithTrap)) {
+    D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+      << lastArgumentForMask(D, Args, NotAllowedWithTrap)
       << "-fsanitize-undefined-trap-on-error";
   }
 
-  // Only one runtime library can be used at once.
-  bool NeedsAsan = needsAsanRt();
-  bool NeedsTsan = needsTsanRt();
-  bool NeedsMsan = needsMsanRt();
-  bool NeedsLsan = needsLeakDetection();
+  // Check for incompatible sanitizers.
+  bool NeedsAsan = Sanitizers.has(SanitizerKind::Address);
+  bool NeedsTsan = Sanitizers.has(SanitizerKind::Thread);
+  bool NeedsMsan = Sanitizers.has(SanitizerKind::Memory);
+  bool NeedsLsan = Sanitizers.has(SanitizerKind::Leak);
   if (NeedsAsan && NeedsTsan)
-    D.Diag(diag::err_drv_argument_not_allowed_with)
-      << lastArgumentForKind(D, Args, NeedsAsanRt)
-      << lastArgumentForKind(D, Args, NeedsTsanRt);
+    D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+      << lastArgumentForKind(D, Args, SanitizerKind::Address)
+      << lastArgumentForKind(D, Args, SanitizerKind::Thread);
   if (NeedsAsan && NeedsMsan)
-    D.Diag(diag::err_drv_argument_not_allowed_with)
-      << lastArgumentForKind(D, Args, NeedsAsanRt)
-      << lastArgumentForKind(D, Args, NeedsMsanRt);
+    D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+      << lastArgumentForKind(D, Args, SanitizerKind::Address)
+      << lastArgumentForKind(D, Args, SanitizerKind::Memory);
   if (NeedsTsan && NeedsMsan)
-    D.Diag(diag::err_drv_argument_not_allowed_with)
-      << lastArgumentForKind(D, Args, NeedsTsanRt)
-      << lastArgumentForKind(D, Args, NeedsMsanRt);
+    D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+      << lastArgumentForKind(D, Args, SanitizerKind::Thread)
+      << lastArgumentForKind(D, Args, SanitizerKind::Memory);
   if (NeedsLsan && NeedsTsan)
-    D.Diag(diag::err_drv_argument_not_allowed_with)
-      << lastArgumentForKind(D, Args, NeedsLeakDetection)
-      << lastArgumentForKind(D, Args, NeedsTsanRt);
+    D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+      << lastArgumentForKind(D, Args, SanitizerKind::Leak)
+      << lastArgumentForKind(D, Args, SanitizerKind::Thread);
   if (NeedsLsan && NeedsMsan)
-    D.Diag(diag::err_drv_argument_not_allowed_with)
-      << lastArgumentForKind(D, Args, NeedsLeakDetection)
-      << lastArgumentForKind(D, Args, NeedsMsanRt);
+    D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+      << lastArgumentForKind(D, Args, SanitizerKind::Leak)
+      << lastArgumentForKind(D, Args, SanitizerKind::Memory);
   // FIXME: Currently -fsanitize=leak is silently ignored in the presence of
   // -fsanitize=address. Perhaps it should print an error, or perhaps
   // -f(-no)sanitize=leak should change whether leak detection is enabled by
@@ -120,11 +232,11 @@ SanitizerArgs::SanitizerArgs(const ToolC
         std::unique_ptr<llvm::SpecialCaseList> SCL(
             llvm::SpecialCaseList::create(BLPath, BLError));
         if (!SCL.get())
-          D.Diag(diag::err_drv_malformed_sanitizer_blacklist) << BLError;
+          D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError;
         else
           BlacklistFile = BLPath;
       } else {
-        D.Diag(diag::err_drv_no_such_file) << BLPath;
+        D.Diag(clang::diag::err_drv_no_such_file) << BLPath;
       }
     }
   } else {
@@ -150,7 +262,7 @@ SanitizerArgs::SanitizerArgs(const ToolC
         StringRef S = A->getValue();
         if (S.getAsInteger(0, MsanTrackOrigins) || MsanTrackOrigins < 0 ||
             MsanTrackOrigins > 2) {
-          D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+          D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
         }
       }
     }
@@ -163,7 +275,7 @@ SanitizerArgs::SanitizerArgs(const ToolC
       // Legal values are 0..4.
       if (S.getAsInteger(0, SanitizeCoverage) || SanitizeCoverage < 0 ||
           SanitizeCoverage > 4)
-        D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+        D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
     }
   }
 
@@ -179,7 +291,7 @@ SanitizerArgs::SanitizerArgs(const ToolC
         // Legal values are 0 and 1, 2, but in future we may add more levels.
         if (S.getAsInteger(0, AsanFieldPadding) || AsanFieldPadding < 0 ||
             AsanFieldPadding > 2) {
-          D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << S;
+          D.Diag(clang::diag::err_drv_invalid_value) << A->getAsString(Args) << S;
         }
     }
 
@@ -191,10 +303,10 @@ SanitizerArgs::SanitizerArgs(const ToolC
       case options::OPT__SLASH_MTd:
       case options::OPT__SLASH_MDd:
       case options::OPT__SLASH_LDd:
-        D.Diag(diag::err_drv_argument_not_allowed_with)
+        D.Diag(clang::diag::err_drv_argument_not_allowed_with)
             << WindowsDebugRTArg->getAsString(Args)
-            << lastArgumentForKind(D, Args, NeedsAsanRt);
-        D.Diag(diag::note_drv_address_sanitizer_debug_runtime);
+            << lastArgumentForKind(D, Args, SanitizerKind::Address);
+        D.Diag(clang::diag::note_drv_address_sanitizer_debug_runtime);
       }
     }
   }
@@ -206,11 +318,11 @@ SanitizerArgs::SanitizerArgs(const ToolC
 
 void SanitizerArgs::addArgs(const llvm::opt::ArgList &Args,
                             llvm::opt::ArgStringList &CmdArgs) const {
-  if (!Kind)
+  if (Sanitizers.empty())
     return;
   SmallString<256> SanitizeOpt("-fsanitize=");
 #define SANITIZER(NAME, ID) \
-  if (Kind & ID) \
+  if (Sanitizers.has(SanitizerKind::ID)) \
     SanitizeOpt += NAME ",";
 #include "clang/Basic/Sanitizers.def"
   SanitizeOpt.pop_back();
@@ -231,11 +343,31 @@ void SanitizerArgs::addArgs(const llvm::
     CmdArgs.push_back(Args.MakeArgString("-fsanitize-coverage=" +
                                          llvm::utostr(SanitizeCoverage)));
   // Workaround for PR16386.
-  if (needsMsanRt())
+  if (Sanitizers.has(SanitizerKind::Memory))
     CmdArgs.push_back(Args.MakeArgString("-fno-assume-sane-operator-new"));
 }
 
-unsigned SanitizerArgs::parse(const char *Value) {
+bool SanitizerArgs::getDefaultBlacklist(const Driver &D, std::string &BLPath) {
+  const char *BlacklistFile = nullptr;
+  if (Sanitizers.has(SanitizerKind::Address))
+    BlacklistFile = "asan_blacklist.txt";
+  else if (Sanitizers.has(SanitizerKind::Memory))
+    BlacklistFile = "msan_blacklist.txt";
+  else if (Sanitizers.has(SanitizerKind::Thread))
+    BlacklistFile = "tsan_blacklist.txt";
+  else if (Sanitizers.has(SanitizerKind::DataFlow))
+    BlacklistFile = "dfsan_abilist.txt";
+
+  if (BlacklistFile) {
+    SmallString<64> Path(D.ResourceDir);
+    llvm::sys::path::append(Path, BlacklistFile);
+    BLPath = Path.str();
+    return true;
+  }
+  return false;
+}
+
+unsigned parseValue(const char *Value) {
   unsigned ParsedKind = llvm::StringSwitch<SanitizeKind>(Value)
 #define SANITIZER(NAME, ID) .Case(NAME, ID)
 #define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID##Group)
@@ -244,44 +376,21 @@ unsigned SanitizerArgs::parse(const char
   return ParsedKind;
 }
 
-unsigned SanitizerArgs::expandGroups(unsigned Kinds) {
+unsigned expandGroups(unsigned Kinds) {
 #define SANITIZER(NAME, ID)
 #define SANITIZER_GROUP(NAME, ID, ALIAS) if (Kinds & ID##Group) Kinds |= ID;
 #include "clang/Basic/Sanitizers.def"
   return Kinds;
 }
 
-void SanitizerArgs::filterUnsupportedMask(const ToolChain &TC, unsigned &Kinds,
-                                          unsigned Mask,
-                                          const llvm::opt::ArgList &Args,
-                                          const llvm::opt::Arg *A,
-                                          bool DiagnoseErrors,
-                                          unsigned &DiagnosedKinds) {
-  unsigned MaskedKinds = Kinds & Mask;
-  if (!MaskedKinds)
-    return;
-  Kinds &= ~Mask;
-  // Do we have new kinds to diagnose?
-  if (DiagnoseErrors && (DiagnosedKinds & MaskedKinds) != MaskedKinds) {
-    // Only diagnose the new kinds.
-    std::string Desc =
-        describeSanitizeArg(Args, A, MaskedKinds & ~DiagnosedKinds);
-    TC.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
-        << Desc << TC.getTriple().str();
-    DiagnosedKinds |= MaskedKinds;
-  }
-}
-
-unsigned SanitizerArgs::filterUnsupportedKinds(const ToolChain &TC,
-                                               unsigned Kinds,
-                                               const llvm::opt::ArgList &Args,
-                                               const llvm::opt::Arg *A,
-                                               bool DiagnoseErrors,
-                                               unsigned &DiagnosedKinds) {
+unsigned filterUnsupportedKinds(const ToolChain &TC, unsigned Kinds,
+                                const llvm::opt::Arg *A, bool DiagnoseErrors,
+                                unsigned &DiagnosedKinds) {
   bool IsFreeBSD = TC.getTriple().getOS() == llvm::Triple::FreeBSD;
   bool IsLinux = TC.getTriple().getOS() == llvm::Triple::Linux;
   bool IsX86 = TC.getTriple().getArch() == llvm::Triple::x86;
   bool IsX86_64 = TC.getTriple().getArch() == llvm::Triple::x86_64;
+
   unsigned KindsToFilterOut = 0;
   if (!(IsLinux && IsX86_64)) {
     KindsToFilterOut |= Memory | DataFlow;
@@ -292,64 +401,70 @@ unsigned SanitizerArgs::filterUnsupporte
   if (!(IsLinux && (IsX86 || IsX86_64))) {
     KindsToFilterOut |= Function;
   }
-  filterUnsupportedMask(TC, Kinds, KindsToFilterOut, Args, A, DiagnoseErrors,
-                        DiagnosedKinds);
-  return Kinds;
+  KindsToFilterOut &= Kinds;
+
+  // Do we have new kinds to diagnose?
+  unsigned KindsToDiagnose = KindsToFilterOut & ~DiagnosedKinds;
+  if (DiagnoseErrors && KindsToDiagnose) {
+    // Only diagnose the new kinds.
+    std::string Desc = describeSanitizeArg(A, KindsToDiagnose);
+    TC.getDriver().Diag(clang::diag::err_drv_unsupported_opt_for_target)
+        << Desc << TC.getTriple().str();
+    DiagnosedKinds |= KindsToFilterOut;
+  }
+
+  return Kinds & ~KindsToFilterOut;
 }
 
-unsigned SanitizerArgs::parse(const Driver &D, const llvm::opt::Arg *A,
-                              bool DiagnoseErrors) {
+unsigned parseArgValues(const Driver &D, const llvm::opt::Arg *A,
+                        bool DiagnoseErrors) {
   unsigned Kind = 0;
   for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
-    if (unsigned K = parse(A->getValue(I)))
+    if (unsigned K = parseValue(A->getValue(I)))
       Kind |= K;
     else if (DiagnoseErrors)
-      D.Diag(diag::err_drv_unsupported_option_argument)
+      D.Diag(clang::diag::err_drv_unsupported_option_argument)
         << A->getOption().getName() << A->getValue(I);
   }
   return Kind;
 }
 
-bool SanitizerArgs::parse(const Driver &D, const llvm::opt::ArgList &Args,
-                          const llvm::opt::Arg *A, unsigned &Add,
-                          unsigned &Remove, bool DiagnoseErrors) {
+bool parseArgument(const Driver &D, const llvm::opt::Arg *A, unsigned &Add,
+                   unsigned &Remove, bool DiagnoseErrors) {
   Add = 0;
   Remove = 0;
   if (A->getOption().matches(options::OPT_fsanitize_EQ)) {
-    Add = parse(D, A, DiagnoseErrors);
-  } else if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) {
-    Remove = parse(D, A, DiagnoseErrors);
-  } else {
-    // Flag is not relevant to sanitizers.
-    return false;
+    Add = parseArgValues(D, A, DiagnoseErrors);
+    return true;
   }
-  return true;
+  if (A->getOption().matches(options::OPT_fno_sanitize_EQ)) {
+    Remove = parseArgValues(D, A, DiagnoseErrors);
+    return true;
+  }
+  return false;
 }
 
-std::string SanitizerArgs::lastArgumentForKind(const Driver &D,
-                                               const llvm::opt::ArgList &Args,
-                                               unsigned Kind) {
+std::string lastArgumentForMask(const Driver &D, const llvm::opt::ArgList &Args,
+                                unsigned Mask) {
   for (llvm::opt::ArgList::const_reverse_iterator I = Args.rbegin(),
                                                   E = Args.rend();
        I != E; ++I) {
     unsigned Add, Remove;
-    if (parse(D, Args, *I, Add, Remove, false) &&
-        (expandGroups(Add) & Kind))
-      return describeSanitizeArg(Args, *I, Kind);
-    Kind &= ~Remove;
+    if (parseArgument(D, *I, Add, Remove, false) &&
+        (expandGroups(Add) & Mask))
+      return describeSanitizeArg(*I, Mask);
+    Mask &= ~Remove;
   }
   llvm_unreachable("arg list didn't provide expected value");
 }
 
-std::string SanitizerArgs::describeSanitizeArg(const llvm::opt::ArgList &Args,
-                                               const llvm::opt::Arg *A,
-                                               unsigned Mask) {
-  if (!A->getOption().matches(options::OPT_fsanitize_EQ))
-    return A->getAsString(Args);
+std::string describeSanitizeArg(const llvm::opt::Arg *A, unsigned Mask) {
+  assert(A->getOption().matches(options::OPT_fsanitize_EQ)
+         && "Invalid argument in describeSanitizerArg!");
 
   std::string Sanitizers;
   for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) {
-    if (expandGroups(parse(A->getValue(I))) & Mask) {
+    if (expandGroups(parseValue(A->getValue(I))) & Mask) {
       if (!Sanitizers.empty())
         Sanitizers += ",";
       Sanitizers += A->getValue(I);
@@ -359,23 +474,3 @@ std::string SanitizerArgs::describeSanit
   assert(!Sanitizers.empty() && "arg didn't provide expected value");
   return "-fsanitize=" + Sanitizers;
 }
-
-bool SanitizerArgs::getDefaultBlacklist(const Driver &D, std::string &BLPath) {
-  const char *BlacklistFile = nullptr;
-  if (Kind & NeedsAsanRt)
-    BlacklistFile = "asan_blacklist.txt";
-  else if (Kind & NeedsMsanRt)
-    BlacklistFile = "msan_blacklist.txt";
-  else if (Kind & NeedsTsanRt)
-    BlacklistFile = "tsan_blacklist.txt";
-  else if (Kind & NeedsDfsanRt)
-    BlacklistFile = "dfsan_abilist.txt";
-
-  if (BlacklistFile) {
-    SmallString<64> Path(D.ResourceDir);
-    llvm::sys::path::append(Path, BlacklistFile);
-    BLPath = Path.str();
-    return true;
-  }
-  return false;
-}





More information about the cfe-commits mailing list