Issue 559: check type declaration uniqueness

Adds PassTypeUnique to the validator.
Disallows repeated declarations of all types except for aggregates.
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 631b1f7..0c4e82e 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -198,6 +198,7 @@
   ${CMAKE_CURRENT_SOURCE_DIR}/validate_datarules.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/validate_decorations.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/validate_layout.cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/validate_type_unique.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/decoration.h
   ${CMAKE_CURRENT_SOURCE_DIR}/val/basic_block.cpp
   ${CMAKE_CURRENT_SOURCE_DIR}/val/construct.cpp
diff --git a/source/val/validation_state.cpp b/source/val/validation_state.cpp
index d125c8c..7a9c591 100644
--- a/source/val/validation_state.cpp
+++ b/source/val/validation_state.cpp
@@ -400,4 +400,23 @@
 uint32_t ValidationState_t::getIdBound() const { return id_bound_; }
 
 void ValidationState_t::setIdBound(const uint32_t bound) { id_bound_ = bound; }
+
+bool ValidationState_t::RegisterUniqueTypeDeclaration(
+    const spv_parsed_instruction_t& inst) {
+  std::vector<uint32_t> key;
+  key.push_back(static_cast<uint32_t>(inst.opcode));
+  for (int index = 0; index < inst.num_operands; ++index) {
+    const spv_parsed_operand_t& operand = inst.operands[index];
+
+    if (operand.type == SPV_OPERAND_TYPE_RESULT_ID) continue;
+
+    const int words_begin = operand.offset;
+    const int words_end = words_begin + operand.num_words;
+    assert(words_end <= static_cast<int>(inst.num_words));
+
+    key.insert(key.end(), inst.words + words_begin, inst.words + words_end);
+  }
+
+  return unique_type_declarations_.insert(std::move(key)).second;
+}
 }  /// namespace libspirv
diff --git a/source/val/validation_state.h b/source/val/validation_state.h
index ac845b0..686685e 100644
--- a/source/val/validation_state.h
+++ b/source/val/validation_state.h
@@ -16,6 +16,7 @@
 #define LIBSPIRV_VAL_VALIDATIONSTATE_H_
 
 #include <deque>
+#include <set>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
@@ -304,6 +305,10 @@
   // Returns the state of optional features.
   const Feature& features() const { return features_; }
 
+  /// Adds the instruction data to unique_type_declarations_.
+  /// Returns false if an identical type declaration already exists.
+  bool RegisterUniqueTypeDeclaration(const spv_parsed_instruction_t& inst);
+
  private:
   ValidationState_t(const ValidationState_t&);
 
@@ -371,6 +376,12 @@
   /// Stores the list of decorations for a given <id>
   std::unordered_map<uint32_t, std::vector<Decoration>> id_decorations_;
 
+  /// Stores type declarations which need to be unique (i.e. non-aggregates),
+  /// in the form [opcode, operand words], result_id is not stored.
+  /// Using ordered set to avoid the need for a vector hash function.
+  /// The size of this container is expected not to exceed double-digits.
+  std::set<std::vector<uint32_t>> unique_type_declarations_;
+
   AssemblyGrammar grammar_;
 
   SpvAddressingModel addressing_model_;
diff --git a/source/validate.cpp b/source/validate.cpp
index de4cc1a..f1fd97d 100644
--- a/source/validate.cpp
+++ b/source/validate.cpp
@@ -140,6 +140,7 @@
   if (auto error = ModuleLayoutPass(_, inst)) return error;
   if (auto error = CfgPass(_, inst)) return error;
   if (auto error = InstructionPass(_, inst)) return error;
+  if (auto error = TypeUniquePass(_, inst)) return error;
 
   return SPV_SUCCESS;
 }
diff --git a/source/validate.h b/source/validate.h
index a1c3e54..6d1ecac 100644
--- a/source/validate.h
+++ b/source/validate.h
@@ -154,6 +154,11 @@
 /// Performs decoration validation.
 spv_result_t ValidateDecorations(ValidationState_t& _);
 
+/// Validates that type declarations are unique, unless multiple declarations
+/// of the same data type are allowed by the specification.
+/// (see section 2.8 Types and Variables)
+spv_result_t TypeUniquePass(ValidationState_t& _,
+                            const spv_parsed_instruction_t* inst);
 }  // namespace libspirv
 
 /// @brief Validate the ID usage of the instruction stream
diff --git a/source/validate_type_unique.cpp b/source/validate_type_unique.cpp
new file mode 100644
index 0000000..857a0f5
--- /dev/null
+++ b/source/validate_type_unique.cpp
@@ -0,0 +1,48 @@
+// Copyright (c) 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Ensures type declarations are unique unless allowed by the specification.
+
+#include "validate.h"
+
+#include "diagnostic.h"
+#include "opcode.h"
+#include "val/instruction.h"
+#include "val/validation_state.h"
+
+namespace libspirv {
+
+// Validates that type declarations are unique, unless multiple declarations
+// of the same data type are allowed by the specification.
+// (see section 2.8 Types and Variables)
+spv_result_t TypeUniquePass(ValidationState_t& _,
+                            const spv_parsed_instruction_t* inst) {
+  const SpvOp opcode = static_cast<SpvOp>(inst->opcode);
+  if (spvOpcodeGeneratesType(opcode)) {
+    if (opcode == SpvOpTypeArray || opcode == SpvOpTypeStruct) {
+      // Duplicate declarations of aggregates are allowed.
+      return SPV_SUCCESS;
+    }
+
+    if (!_.RegisterUniqueTypeDeclaration(*inst)) {
+      return _.diag(SPV_ERROR_INVALID_DATA)
+          << "Duplicate non-aggregate type declarations are not allowed."
+          << " Opcode: " << inst->opcode;
+    }
+  }
+
+  return SPV_SUCCESS;
+}
+
+}  // namespace libspirv
diff --git a/test/val/CMakeLists.txt b/test/val/CMakeLists.txt
index 8c41185..3b9229d 100644
--- a/test/val/CMakeLists.txt
+++ b/test/val/CMakeLists.txt
@@ -69,6 +69,12 @@
   LIBS ${SPIRV_TOOLS}
 )
 
+add_spvtools_unittest(TARGET val_type_unique
+	SRCS val_type_unique_test.cpp
+       ${VAL_TEST_COMMON_SRCS}
+  LIBS ${SPIRV_TOOLS}
+)
+
 add_spvtools_unittest(TARGET val_limits
 	SRCS val_limits_test.cpp
        ${VAL_TEST_COMMON_SRCS}
diff --git a/test/val/val_capability_test.cpp b/test/val/val_capability_test.cpp
index 6ffded7..eb64b46 100644
--- a/test/val/val_capability_test.cpp
+++ b/test/val/val_capability_test.cpp
@@ -419,6 +419,13 @@
   "           OpReturn"
   "           OpFunctionEnd ";
 
+const char kVoidFVoid2[] = \
+  " %void_f = OpTypeFunction %voidt"
+  " %func   = OpFunction %voidt None %void_f"
+  " %label  = OpLabel"
+  "           OpReturn"
+  "           OpFunctionEnd ";
+
 INSTANTIATE_TEST_CASE_P(ExecutionModel, ValidateCapability,
                         Combine(
                             ValuesIn(AllCapabilities()),
@@ -717,43 +724,43 @@
           string(kOpenCLMemoryModel) +
           string(" OpEntryPoint Kernel %func \"compute\"") +
           " %voidt = OpTypeVoid"
-          " %imgt = OpTypeImage %voidt 1D 0 0 0 0 Unknown" + string(kVoidFVoid),
+          " %imgt = OpTypeImage %voidt 1D 0 0 0 0 Unknown" + string(kVoidFVoid2),
           Sampled1DDependencies()),
 make_pair(" OpCapability ImageBasic" +
           string(kOpenCLMemoryModel) +
           string(" OpEntryPoint Kernel %func \"compute\"") +
           " %voidt = OpTypeVoid"
-          " %imgt = OpTypeImage %voidt 2D 0 0 0 0 Unknown" + string(kVoidFVoid),
+          " %imgt = OpTypeImage %voidt 2D 0 0 0 0 Unknown" + string(kVoidFVoid2),
           AllCapabilities()),
 make_pair(" OpCapability ImageBasic" +
           string(kOpenCLMemoryModel) +
           string(" OpEntryPoint Kernel %func \"compute\"") +
           " %voidt = OpTypeVoid"
-          " %imgt = OpTypeImage %voidt 3D 0 0 0 0 Unknown" + string(kVoidFVoid),
+          " %imgt = OpTypeImage %voidt 3D 0 0 0 0 Unknown" + string(kVoidFVoid2),
           AllCapabilities()),
 make_pair(" OpCapability ImageBasic" +
           string(kOpenCLMemoryModel) +
           string(" OpEntryPoint Kernel %func \"compute\"") +
           " %voidt = OpTypeVoid"
-          " %imgt = OpTypeImage %voidt Cube 0 0 0 0 Unknown" + string(kVoidFVoid),
+          " %imgt = OpTypeImage %voidt Cube 0 0 0 0 Unknown" + string(kVoidFVoid2),
           ShaderDependencies()),
 make_pair(" OpCapability ImageBasic" +
           string(kOpenCLMemoryModel) +
           string(" OpEntryPoint Kernel %func \"compute\"") +
           " %voidt = OpTypeVoid"
-          " %imgt = OpTypeImage %voidt Rect 0 0 0 0 Unknown" + string(kVoidFVoid),
+          " %imgt = OpTypeImage %voidt Rect 0 0 0 0 Unknown" + string(kVoidFVoid2),
           SampledRectDependencies()),
 make_pair(" OpCapability ImageBasic" +
           string(kOpenCLMemoryModel) +
           string(" OpEntryPoint Kernel %func \"compute\"") +
           " %voidt = OpTypeVoid"
-          " %imgt = OpTypeImage %voidt Buffer 0 0 0 0 Unknown" + string(kVoidFVoid),
+          " %imgt = OpTypeImage %voidt Buffer 0 0 0 0 Unknown" + string(kVoidFVoid2),
           SampledBufferDependencies()),
 make_pair(" OpCapability ImageBasic" +
           string(kOpenCLMemoryModel) +
           string(" OpEntryPoint Kernel %func \"compute\"") +
           " %voidt = OpTypeVoid"
-          " %imgt = OpTypeImage %voidt SubpassData 0 0 0 2 Unknown" + string(kVoidFVoid),
+          " %imgt = OpTypeImage %voidt SubpassData 0 0 0 2 Unknown" + string(kVoidFVoid2),
           vector<string>{"InputAttachment"})
 )),);
 
diff --git a/test/val/val_data_test.cpp b/test/val/val_data_test.cpp
index 3c4ffed..f756e3a 100644
--- a/test/val/val_data_test.cpp
+++ b/test/val/val_data_test.cpp
@@ -42,7 +42,6 @@
      OpCapability Shader
      OpCapability Linkage
      OpMemoryModel Logical GLSL450
-%1 = OpTypeFloat 32
 )";
 string header_with_addresses = R"(
      OpCapability Addresses
@@ -56,7 +55,6 @@
      OpCapability Vector16
      OpCapability Linkage
      OpMemoryModel Logical GLSL450
-%1 = OpTypeFloat 32
 )";
 string header_with_int8 = R"(
      OpCapability Shader
@@ -108,72 +106,105 @@
 string invalid_num_bits_error = "Invalid number of bits";
 
 TEST_F(ValidateData, vec0) {
-  string str = header + "%2 = OpTypeVector %1 0";
+  string str = header + R"(
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 0
+)";
   CompileSuccessfully(str.c_str());
   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
   EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
 }
 
 TEST_F(ValidateData, vec1) {
-  string str = header + "%2 = OpTypeVector %1 1";
+  string str = header + R"(
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 1
+)";
   CompileSuccessfully(str.c_str());
   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
   EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
 }
 
 TEST_F(ValidateData, vec2) {
-  string str = header + "%2 = OpTypeVector %1 2";
+  string str = header + R"(
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 2
+)";
   CompileSuccessfully(str.c_str());
   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
 }
 
 TEST_F(ValidateData, vec3) {
-  string str = header + "%2 = OpTypeVector %1 3";
+  string str = header + R"(
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 3
+)";
   CompileSuccessfully(str.c_str());
   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
 }
 
 TEST_F(ValidateData, vec4) {
-  string str = header + "%2 = OpTypeVector %1 4";
+  string str = header + R"(
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 4
+)";
   CompileSuccessfully(str.c_str());
   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
 }
 
 TEST_F(ValidateData, vec5) {
-  string str = header + "%2 = OpTypeVector %1 5";
+  string str = header + R"(
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 5
+)";
   CompileSuccessfully(str.c_str());
   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
   EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
 }
 
 TEST_F(ValidateData, vec8) {
-  string str = header + "%2 = OpTypeVector %1 8";
+  string str = header + R"(
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 8
+)";
   CompileSuccessfully(str.c_str());
   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_cap_error));
 }
 
 TEST_F(ValidateData, vec8_with_capability) {
-  string str = header_with_vec16_cap + "%2 = OpTypeVector %1 8";
+  string str = header_with_vec16_cap + R"(
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 8
+)";
   CompileSuccessfully(str.c_str());
   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
 }
 
 TEST_F(ValidateData, vec16) {
-  string str = header + "%2 = OpTypeVector %1 16";
+  string str = header + R"(
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 8
+)";
   CompileSuccessfully(str.c_str());
   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
   EXPECT_THAT(getDiagnosticString(), HasSubstr(missing_cap_error));
 }
 
 TEST_F(ValidateData, vec16_with_capability) {
-  string str = header_with_vec16_cap + "%2 = OpTypeVector %1 16";
+  string str = header_with_vec16_cap + R"(
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 16
+)";
   CompileSuccessfully(str.c_str());
   ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
 }
 
 TEST_F(ValidateData, vec15) {
-  string str = header + "%2 = OpTypeVector %1 15";
+  string str = header + R"(
+%1 = OpTypeFloat 32
+%2 = OpTypeVector %1 15
+)";
   CompileSuccessfully(str.c_str());
   ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
   EXPECT_THAT(getDiagnosticString(), HasSubstr(invalid_comp_error));
diff --git a/test/val/val_type_unique_test.cpp b/test/val/val_type_unique_test.cpp
new file mode 100644
index 0000000..f51cd9b
--- /dev/null
+++ b/test/val/val_type_unique_test.cpp
@@ -0,0 +1,219 @@
+// Copyright (c) 2017 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Tests for unique type declaration rules validator.
+
+#include <string>
+
+#include "gmock/gmock.h"
+#include "unit_spirv.h"
+#include "val_fixtures.h"
+
+namespace {
+
+using ::testing::HasSubstr;
+
+using std::string;
+using std::pair;
+
+using ValidateTypeUnique = spvtest::ValidateBase<bool>;
+
+const string& GetHeader() {
+  static const string header = R"(
+OpCapability Shader
+OpCapability Linkage
+OpMemoryModel Logical GLSL450
+%floatt = OpTypeFloat 32
+%vec2t = OpTypeVector %floatt 2
+%vec3t = OpTypeVector %floatt 3
+%vec4t = OpTypeVector %floatt 4
+%mat22t = OpTypeMatrix %vec2t 2
+%mat33t = OpTypeMatrix %vec3t 3
+%mat44t = OpTypeMatrix %vec4t 4
+%intt = OpTypeInt 32 1
+%uintt = OpTypeInt 32 0
+%num3 = OpConstant %uintt 3
+%const3 = OpConstant %uintt 3
+%val3 = OpConstant %uintt 3
+%array = OpTypeArray %vec3t %num3
+%struct = OpTypeStruct %floatt %floatt %vec3t
+%boolt = OpTypeBool
+%array2 = OpTypeArray %vec3t %num3
+%voidt = OpTypeVoid
+%vfunct = OpTypeFunction %voidt
+%struct2 = OpTypeStruct %floatt %floatt %vec3t
+%false = OpConstantFalse %boolt
+%true = OpConstantTrue %boolt
+)";
+
+  return header;
+}
+
+const string& GetBody() {
+  static const string body = R"(
+%main = OpFunction %voidt None %vfunct
+%mainl = OpLabel
+%a = OpIAdd %uintt %const3 %val3
+%b = OpIAdd %uintt %const3 %val3
+OpSelectionMerge %endl None
+OpBranchConditional %true %truel %falsel
+%truel = OpLabel
+%add1 = OpIAdd %uintt %a %b
+%add2 = OpIAdd %uintt %a %b
+OpBranch %endl
+%falsel = OpLabel
+%sub1 = OpISub %uintt %a %b
+%sub2 = OpISub %uintt %a %b
+OpBranch %endl
+%endl = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  return body;
+}
+
+// Returns expected error string if |opcode| produces a duplicate type
+// declaration.
+string GetErrorString(SpvOp opcode) {
+  return "Duplicate non-aggregate type declarations are not allowed. Opcode: "
+      + std::to_string(opcode);
+}
+
+TEST_F(ValidateTypeUnique, success) {
+  string str = GetHeader() + GetBody();
+  CompileSuccessfully(str.c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+TEST_F(ValidateTypeUnique, duplicate_void) {
+  string str = GetHeader() + R"(
+%boolt2 = OpTypeVoid
+)" + GetBody();
+  CompileSuccessfully(str.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr(GetErrorString(SpvOpTypeVoid)));
+}
+
+TEST_F(ValidateTypeUnique, duplicate_bool) {
+  string str = GetHeader() + R"(
+%boolt2 = OpTypeBool
+)" + GetBody();
+  CompileSuccessfully(str.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr(GetErrorString(SpvOpTypeBool)));
+}
+
+TEST_F(ValidateTypeUnique, duplicate_int) {
+  string str = GetHeader() + R"(
+%uintt2 = OpTypeInt 32 0
+)" + GetBody();
+  CompileSuccessfully(str.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr(GetErrorString(SpvOpTypeInt)));
+}
+
+TEST_F(ValidateTypeUnique, duplicate_float) {
+  string str = GetHeader() + R"(
+%floatt2 = OpTypeFloat 32
+)" + GetBody();
+  CompileSuccessfully(str.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(), HasSubstr(GetErrorString(SpvOpTypeFloat)));
+}
+
+TEST_F(ValidateTypeUnique, duplicate_vec3) {
+  string str = GetHeader() + R"(
+%vec3t2 = OpTypeVector %floatt 3
+)" + GetBody();
+  CompileSuccessfully(str.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr(GetErrorString(SpvOpTypeVector)));
+}
+
+TEST_F(ValidateTypeUnique, duplicate_mat33) {
+  string str = GetHeader() + R"(
+%mat33t2 = OpTypeMatrix %vec3t 3
+)" + GetBody();
+  CompileSuccessfully(str.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr(GetErrorString(SpvOpTypeMatrix)));
+}
+
+TEST_F(ValidateTypeUnique, duplicate_vfunc) {
+  string str = GetHeader() + R"(
+%vfunct2 = OpTypeFunction %voidt
+)" + GetBody();
+  CompileSuccessfully(str.c_str());
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA, ValidateInstructions());
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr(GetErrorString(SpvOpTypeFunction)));
+}
+
+TEST_F(ValidateTypeUnique, duplicate_pipe_storage) {
+  string str = R"(
+OpCapability Addresses
+OpCapability Kernel
+OpCapability Linkage
+OpCapability Pipes
+OpCapability PipeStorage
+OpMemoryModel Physical32 OpenCL
+%ps = OpTypePipeStorage
+%ps2 = OpTypePipeStorage
+)";
+  CompileSuccessfully(str.c_str(), SPV_ENV_UNIVERSAL_1_1);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr(GetErrorString(SpvOpTypePipeStorage)));
+}
+
+TEST_F(ValidateTypeUnique, duplicate_named_barrier) {
+  string str = R"(
+OpCapability Addresses
+OpCapability Kernel
+OpCapability Linkage
+OpCapability NamedBarrier
+OpMemoryModel Physical32 OpenCL
+%nb = OpTypeNamedBarrier
+%nb2 = OpTypeNamedBarrier
+)";
+  CompileSuccessfully(str.c_str(), SPV_ENV_UNIVERSAL_1_1);
+  ASSERT_EQ(SPV_ERROR_INVALID_DATA,
+            ValidateInstructions(SPV_ENV_UNIVERSAL_1_1));
+  EXPECT_THAT(getDiagnosticString(),
+              HasSubstr(GetErrorString(SpvOpTypeNamedBarrier)));
+}
+
+TEST_F(ValidateTypeUnique, duplicate_forward_pointer) {
+  string str = R"(
+OpCapability Addresses
+OpCapability Kernel
+OpCapability GenericPointer
+OpCapability Linkage
+OpMemoryModel Physical32 OpenCL
+OpTypeForwardPointer %ptr Generic
+OpTypeForwardPointer %ptr2 Generic
+%intt = OpTypeInt 32 0
+%floatt = OpTypeFloat 32
+%ptr = OpTypePointer Generic %intt
+%ptr2 = OpTypePointer Generic %floatt
+)";
+  CompileSuccessfully(str.c_str());
+  ASSERT_EQ(SPV_SUCCESS, ValidateInstructions());
+}
+
+}  // anonymous namespace