linker: Recalculate interface variables (#4784)

* linker: Recalculate interface variables

By resolving extern symbols Entry Points might access variables they
hadn't declared before.

* test/linker: add test to verify linked spir-vs importing functions validate

Without the fix Validate will complain about:

"ERROR: 9: Interface variable id <5> is used by entry point 'bar' id <1>, but is not listed as an interface\n  %5 = OpVariable %_ptr_Input_v3uint Input\n"
diff --git a/source/link/linker.cpp b/source/link/linker.cpp
index 76ce775..3b388cc 100644
--- a/source/link/linker.cpp
+++ b/source/link/linker.cpp
@@ -34,6 +34,7 @@
 #include "source/opt/ir_loader.h"
 #include "source/opt/pass_manager.h"
 #include "source/opt/remove_duplicates_pass.h"
+#include "source/opt/remove_unused_interface_variables_pass.h"
 #include "source/opt/type_manager.h"
 #include "source/spirv_constant.h"
 #include "source/spirv_target_env.h"
@@ -807,11 +808,16 @@
   pass_res = manager.Run(&linked_context);
   if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA;
 
-  // Phase 11: Warn if SPIR-V limits were exceeded
+  // Phase 11: Recompute EntryPoint variables
+  manager.AddPass<opt::RemoveUnusedInterfaceVariablesPass>();
+  pass_res = manager.Run(&linked_context);
+  if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA;
+
+  // Phase 12: Warn if SPIR-V limits were exceeded
   res = VerifyLimits(consumer, linked_context);
   if (res != SPV_SUCCESS) return res;
 
-  // Phase 12: Output the module
+  // Phase 13: Output the module
   linked_context.module()->ToBinary(linked_binary, true);
 
   return SPV_SUCCESS;
diff --git a/test/link/entry_points_test.cpp b/test/link/entry_points_test.cpp
index df7ea20..edf9f42 100644
--- a/test/link/entry_points_test.cpp
+++ b/test/link/entry_points_test.cpp
@@ -104,5 +104,48 @@
                         "GLCompute, was already defined."));
 }
 
+TEST_F(EntryPoints, LinkedVariables) {
+  const std::string body1 = R"(
+               OpCapability Addresses
+OpCapability Linkage
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
+OpDecorate %7 LinkageAttributes "foo" Export
+%1 = OpTypeInt 32 0
+%2 = OpTypeVector %1 3
+%3 = OpTypePointer Input %2
+%4 = OpVariable %3 Input
+%5 = OpTypeVoid
+%6 = OpTypeFunction %5
+%7 = OpFunction %5 None %6
+%8 = OpLabel
+%9 = OpLoad %2 %4 Aligned 32
+OpReturn
+OpFunctionEnd
+)";
+  const std::string body2 = R"(
+OpCapability Linkage
+OpCapability Kernel
+OpMemoryModel Physical64 OpenCL
+OpEntryPoint Kernel %4 "bar"
+OpDecorate %3 LinkageAttributes "foo" Import
+%1 = OpTypeVoid
+%2 = OpTypeFunction %1
+%3 = OpFunction %1 None %2
+OpFunctionEnd
+%4 = OpFunction %1 None %2
+%5 = OpLabel
+%6 = OpFunctionCall %1 %3
+OpReturn
+OpFunctionEnd
+)";
+
+  spvtest::Binary linked_binary;
+  EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary));
+  EXPECT_THAT(GetErrorMessage(), std::string());
+  EXPECT_TRUE(Validate(linked_binary));
+  EXPECT_THAT(GetErrorMessage(), std::string());
+}
+
 }  // namespace
 }  // namespace spvtools
diff --git a/test/link/linker_fixture.h b/test/link/linker_fixture.h
index 7bb1223..d005288 100644
--- a/test/link/linker_fixture.h
+++ b/test/link/linker_fixture.h
@@ -208,6 +208,10 @@
   // Returns the accumulated error messages for the test.
   std::string GetErrorMessage() const { return error_message_; }
 
+  bool Validate(const spvtest::Binary& binary) {
+    return tools_.Validate(binary);
+  }
+
  private:
   spvtools::Context context_;
   spvtools::SpirvTools