Remove the static maps from CheckDecorationsCompatibility (#2327)

* Remove the static maps from CheckDecorationsCompatibility

There are a few data structures in the function
`CheckDecorationsCompatibility` that are allocated using `new` and their
address is stored in a static pointer.  This code pattern causes the
MSVC memory leak checker to say there is a memory leak.  Some people
are interested in keeping that clean.

To work around it, I have replaced them with either a function or an
array of POD types.  The array can be kept as a static directly because
it has a trivial destructor, and we don't have to worry about it being
destroyed too early.

Fixes https://github.com/KhronosGroup/SPIRV-Tools/issues/2317.
diff --git a/source/val/validate_decorations.cpp b/source/val/validate_decorations.cpp
index b76a051..6dd775d 100644
--- a/source/val/validate_decorations.cpp
+++ b/source/val/validate_decorations.cpp
@@ -968,42 +968,64 @@
   return SPV_SUCCESS;
 }
 
+// Returns true if |decoration| cannot be applied to the same id more than once.
+bool AtMostOncePerId(SpvDecoration decoration) {
+  return decoration == SpvDecorationArrayStride;
+}
+
+// Returns true if |decoration| cannot be applied to the same member more than
+// once.
+bool AtMostOncePerMember(SpvDecoration decoration) {
+  switch (decoration) {
+    case SpvDecorationOffset:
+    case SpvDecorationMatrixStride:
+    case SpvDecorationRowMajor:
+    case SpvDecorationColMajor:
+      return true;
+    default:
+      return false;
+  }
+}
+
+// Returns the string name for |decoration|.
+const char* GetDecorationName(SpvDecoration decoration) {
+  switch (decoration) {
+    case SpvDecorationArrayStride:
+      return "ArrayStride";
+    case SpvDecorationOffset:
+      return "Offset";
+    case SpvDecorationMatrixStride:
+      return "MatrixStride";
+    case SpvDecorationRowMajor:
+      return "RowMajor";
+    case SpvDecorationColMajor:
+      return "ColMajor";
+    case SpvDecorationBlock:
+      return "Block";
+    case SpvDecorationBufferBlock:
+      return "BufferBlock";
+    default:
+      return "";
+  }
+}
+
 spv_result_t CheckDecorationsCompatibility(ValidationState_t& vstate) {
-  using AtMostOnceSet = std::unordered_set<SpvDecoration, SpvDecorationHash>;
-  using MutuallyExclusiveSets =
-      std::vector<std::unordered_set<SpvDecoration, SpvDecorationHash>>;
   using PerIDKey = std::tuple<SpvDecoration, uint32_t>;
   using PerMemberKey = std::tuple<SpvDecoration, uint32_t, uint32_t>;
-  using DecorationNameTable =
-      std::unordered_map<SpvDecoration, std::string, SpvDecorationHash>;
 
-  static const auto* const at_most_once_per_id = new AtMostOnceSet{
-      SpvDecorationArrayStride,
-  };
-  static const auto* const at_most_once_per_member = new AtMostOnceSet{
-      SpvDecorationOffset,
-      SpvDecorationMatrixStride,
-      SpvDecorationRowMajor,
-      SpvDecorationColMajor,
-  };
-  static const auto* const mutually_exclusive_per_id =
-      new MutuallyExclusiveSets{
-          {SpvDecorationBlock, SpvDecorationBufferBlock},
-      };
-  static const auto* const mutually_exclusive_per_member =
-      new MutuallyExclusiveSets{
-          {SpvDecorationRowMajor, SpvDecorationColMajor},
-      };
-  // For printing the decoration name.
-  static const auto* const decoration_name = new DecorationNameTable{
-      {SpvDecorationArrayStride, "ArrayStride"},
-      {SpvDecorationOffset, "Offset"},
-      {SpvDecorationMatrixStride, "MatrixStride"},
-      {SpvDecorationRowMajor, "RowMajor"},
-      {SpvDecorationColMajor, "ColMajor"},
-      {SpvDecorationBlock, "Block"},
-      {SpvDecorationBufferBlock, "BufferBlock"},
-  };
+  // An Array of pairs where the decorations in the pair cannot both be applied
+  // to the same id.
+  static const SpvDecoration mutually_exclusive_per_id[][2] = {
+      {SpvDecorationBlock, SpvDecorationBufferBlock}};
+  static const auto num_mutually_exclusive_per_id_pairs =
+      sizeof(mutually_exclusive_per_id) / (2 * sizeof(SpvDecoration));
+
+  // An Array of pairs where the decorations in the pair cannot both be applied
+  // to the same member.
+  static const SpvDecoration mutually_exclusive_per_member[][2] = {
+      {SpvDecorationRowMajor, SpvDecorationColMajor}};
+  static const auto num_mutually_exclusive_per_mem_pairs =
+      sizeof(mutually_exclusive_per_member) / (2 * sizeof(SpvDecoration));
 
   std::set<PerIDKey> seen_per_id;
   std::set<PerMemberKey> seen_per_member;
@@ -1015,26 +1037,31 @@
       const auto dec_type = static_cast<SpvDecoration>(words[2]);
       const auto k = PerIDKey(dec_type, id);
       const auto already_used = !seen_per_id.insert(k).second;
-      if (already_used &&
-          at_most_once_per_id->find(dec_type) != at_most_once_per_id->end()) {
+      if (already_used && AtMostOncePerId(dec_type)) {
         return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
                << "ID '" << id << "' decorated with "
-               << decoration_name->at(dec_type)
+               << GetDecorationName(dec_type)
                << " multiple times is not allowed.";
       }
       // Verify certain mutually exclusive decorations are not both applied on
       // an ID.
-      for (const auto& s : *mutually_exclusive_per_id) {
-        if (s.find(dec_type) == s.end()) continue;
-        for (auto excl_dec_type : s) {
-          if (excl_dec_type == dec_type) continue;
-          const auto excl_k = PerIDKey(excl_dec_type, id);
-          if (seen_per_id.find(excl_k) != seen_per_id.end()) {
-            return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
-                   << "ID '" << id << "' decorated with both "
-                   << decoration_name->at(dec_type) << " and "
-                   << decoration_name->at(excl_dec_type) << " is not allowed.";
-          }
+      for (uint32_t pair_idx = 0;
+           pair_idx < num_mutually_exclusive_per_id_pairs; ++pair_idx) {
+        SpvDecoration excl_dec_type = SpvDecorationMax;
+        if (mutually_exclusive_per_id[pair_idx][0] == dec_type) {
+          excl_dec_type = mutually_exclusive_per_id[pair_idx][1];
+        } else if (mutually_exclusive_per_id[pair_idx][1] == dec_type) {
+          excl_dec_type = mutually_exclusive_per_id[pair_idx][0];
+        } else {
+          continue;
+        }
+
+        const auto excl_k = PerIDKey(excl_dec_type, id);
+        if (seen_per_id.find(excl_k) != seen_per_id.end()) {
+          return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
+                 << "ID '" << id << "' decorated with both "
+                 << GetDecorationName(dec_type) << " and "
+                 << GetDecorationName(excl_dec_type) << " is not allowed.";
         }
       }
     } else if (SpvOpMemberDecorate == inst.opcode()) {
@@ -1043,27 +1070,32 @@
       const auto dec_type = static_cast<SpvDecoration>(words[3]);
       const auto k = PerMemberKey(dec_type, id, member_id);
       const auto already_used = !seen_per_member.insert(k).second;
-      if (already_used && at_most_once_per_member->find(dec_type) !=
-                              at_most_once_per_member->end()) {
+      if (already_used && AtMostOncePerMember(dec_type)) {
         return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
                << "ID '" << id << "', member '" << member_id
-               << "' decorated with " << decoration_name->at(dec_type)
+               << "' decorated with " << GetDecorationName(dec_type)
                << " multiple times is not allowed.";
       }
       // Verify certain mutually exclusive decorations are not both applied on
       // a (ID, member) tuple.
-      for (const auto& s : *mutually_exclusive_per_member) {
-        if (s.find(dec_type) == s.end()) continue;
-        for (auto excl_dec_type : s) {
-          if (excl_dec_type == dec_type) continue;
-          const auto excl_k = PerMemberKey(excl_dec_type, id, member_id);
-          if (seen_per_member.find(excl_k) != seen_per_member.end()) {
-            return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
-                   << "ID '" << id << "', member '" << member_id
-                   << "' decorated with both " << decoration_name->at(dec_type)
-                   << " and " << decoration_name->at(excl_dec_type)
-                   << " is not allowed.";
-          }
+      for (uint32_t pair_idx = 0;
+           pair_idx < num_mutually_exclusive_per_mem_pairs; ++pair_idx) {
+        SpvDecoration excl_dec_type = SpvDecorationMax;
+        if (mutually_exclusive_per_member[pair_idx][0] == dec_type) {
+          excl_dec_type = mutually_exclusive_per_member[pair_idx][1];
+        } else if (mutually_exclusive_per_member[pair_idx][1] == dec_type) {
+          excl_dec_type = mutually_exclusive_per_member[pair_idx][0];
+        } else {
+          continue;
+        }
+
+        const auto excl_k = PerMemberKey(excl_dec_type, id, member_id);
+        if (seen_per_member.find(excl_k) != seen_per_member.end()) {
+          return vstate.diag(SPV_ERROR_INVALID_ID, vstate.FindDef(id))
+                 << "ID '" << id << "', member '" << member_id
+                 << "' decorated with both " << GetDecorationName(dec_type)
+                 << " and " << GetDecorationName(excl_dec_type)
+                 << " is not allowed.";
         }
       }
     }