spirv-fuzz: Avoid passing access chains as parameters (#3112)

This change prevents the spirv-fuzz function outliner from outlining a
region that uses the result of an OpAccessChain not defined inside the
region.  Such accesses were turning into parameters to the outlined
function, and the result of an OpAccessChain cannot be passed as a
function parameter according to the SPIR-V specification.
diff --git a/source/fuzz/transformation_outline_function.cpp b/source/fuzz/transformation_outline_function.cpp
index 95517f5..1d1d48e 100644
--- a/source/fuzz/transformation_outline_function.cpp
+++ b/source/fuzz/transformation_outline_function.cpp
@@ -259,15 +259,22 @@
     }
   }
 
-  // For each region input id -- i.e. every id defined outside the region but
-  // used inside the region -- there needs to be a corresponding fresh id to be
-  // used as a function parameter.
+  // For each region input id, i.e. every id defined outside the region but
+  // used inside the region, ...
   std::map<uint32_t, uint32_t> input_id_to_fresh_id_map =
       PairSequenceToMap(message_.input_id_to_fresh_id());
   for (auto id : GetRegionInputIds(context, region_set, exit_block)) {
+    // There needs to be a corresponding fresh id to be used as a function
+    // parameter.
     if (input_id_to_fresh_id_map.count(id) == 0) {
       return false;
     }
+    // Furthermore, no region input id is allowed to be the result of an access
+    // chain.  This is because region input ids will become function parameters,
+    // and it is not legal to pass an access chain as a function parameter.
+    if (context->get_def_use_mgr()->GetDef(id)->opcode() == SpvOpAccessChain) {
+      return false;
+    }
   }
 
   // For each region output id -- i.e. every id defined inside the region but
diff --git a/test/fuzz/transformation_outline_function_test.cpp b/test/fuzz/transformation_outline_function_test.cpp
index de82ebe..4f828b6 100644
--- a/test/fuzz/transformation_outline_function_test.cpp
+++ b/test/fuzz/transformation_outline_function_test.cpp
@@ -1600,6 +1600,62 @@
   ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
 }
 
+TEST(TransformationOutlineFunctionTest, DoNotOutlineRegionThatUsesAccessChain) {
+  // An access chain result is a pointer, but it cannot be passed as a function
+  // parameter, as it is not a memory object.
+  std::string shader = R"(
+               OpCapability Shader
+          %1 = OpExtInstImport "GLSL.std.450"
+               OpMemoryModel Logical GLSL450
+               OpEntryPoint Fragment %4 "main"
+               OpExecutionMode %4 OriginUpperLeft
+               OpSource ESSL 310
+               OpName %4 "main"
+          %2 = OpTypeVoid
+          %3 = OpTypeFunction %2
+          %6 = OpTypeFloat 32
+          %7 = OpTypeVector %6 4
+          %8 = OpTypePointer Function %7
+          %9 = OpTypePointer Function %6
+         %18 = OpTypeInt 32 0
+         %19 = OpConstant %18 0
+          %4 = OpFunction %2 None %3
+          %5 = OpLabel
+         %10 = OpVariable %8 Function
+               OpBranch %11
+         %11 = OpLabel
+         %12 = OpAccessChain %9 %10 %19
+               OpBranch %13
+         %13 = OpLabel
+         %14 = OpLoad %6 %12
+               OpBranch %15
+         %15 = OpLabel
+               OpReturn
+               OpFunctionEnd
+  )";
+
+  const auto env = SPV_ENV_UNIVERSAL_1_5;
+  const auto consumer = nullptr;
+  const auto context = BuildModule(env, consumer, shader, kFuzzAssembleOption);
+  ASSERT_TRUE(IsValid(env, context.get()));
+
+  FactManager fact_manager;
+
+  TransformationOutlineFunction transformation(
+      /*entry_block*/ 13,
+      /*exit_block*/ 15,
+      /*new_function_struct_return_type_id*/ 200,
+      /*new_function_type_id*/ 201,
+      /*new_function_id*/ 202,
+      /*new_function_region_entry_block*/ 204,
+      /*new_caller_result_id*/ 205,
+      /*new_callee_result_id*/ 206,
+      /*input_id_to_fresh_id*/ {{12, 207}},
+      /*output_id_to_fresh_id*/ {});
+
+  ASSERT_FALSE(transformation.IsApplicable(context.get(), fact_manager));
+}
+
 TEST(TransformationOutlineFunctionTest, Miscellaneous1) {
   // This tests outlining of some non-trivial code.