Report details of at most 3 #pragma shader_stage conflicts

This avoids a potential memory blowup when reporting errors.

Google-internal bug 536206565
diff --git a/glslc/test/pragma_shader_stage.py b/glslc/test/pragma_shader_stage.py
index c0f1f08..d2522b2 100644
--- a/glslc/test/pragma_shader_stage.py
+++ b/glslc/test/pragma_shader_stage.py
@@ -540,6 +540,38 @@
 
 
 @inside_glslc_testsuite('PragmaShaderStage')
+class TestPSSExcessStageConflictReportingCutoffAt3(expect.ErrorMessage):
+    """Tests that if there are more than 3 shader-stage pragma
+    stage conflicts, the details are only provided for three of
+    them, with an additional trailing count of how many more exist."""
+
+    shader = FileShader(
+        """#version 310 es
+        #pragma shader_stage(idontknow)
+        #pragma shader_stage(vertex)
+        void main() {
+            gl_Position = vec4(1.);
+        }
+        #pragma shader_stage(fragment)
+        #pragma shader_stage(fragment)
+        #pragma shader_stage(fragment)
+        #pragma shader_stage(fragment)
+        """, '.glsl')
+    glslc_args = ['-c', shader]
+    expected_error = [
+        shader, ":2: error: '#pragma': invalid stage for 'shader_stage' "
+        "#pragma: 'idontknow'\n",
+        shader, ":3: error: '#pragma': conflicting stages for 'shader_stage' "
+        "#pragma: 'vertex' (was 'idontknow' at ", shader, ':2)\n',
+        shader, ":7: error: '#pragma': conflicting stages for 'shader_stage' "
+        "#pragma: 'fragment' (was 'idontknow' at ", shader, ':2)\n',
+        shader, ":8: error: '#pragma': conflicting stages for 'shader_stage' "
+        "#pragma: 'fragment' (was 'idontknow' at ", shader, ':2)\n',
+        "error: ... 2 more conflicting 'shader_stage' pragmas\n",
+    ]
+
+
+@inside_glslc_testsuite('PragmaShaderStage')
 class TestSpacesAroundPSS(expect.ValidObjectFile):
     """Tests that spaces around #pragma shader_stage() works."""
 
diff --git a/libshaderc_util/src/compiler.cc b/libshaderc_util/src/compiler.cc
index bbd5469..89d9914 100644
--- a/libshaderc_util/src/compiler.cc
+++ b/libshaderc_util/src/compiler.cc
@@ -714,20 +714,30 @@
         first_pragma_stage.str() + "'\n";
   }
 
+  constexpr size_t kMaxReportedConflicts = 3;
+  size_t num_conflicts = 0;
   for (size_t i = 1; i < stages.size(); ++i) {
     const string_piece& current_stage = std::get<2>(stages[i]);
     if (current_stage != first_pragma_stage) {
-      const string_piece& current_filename = std::get<0>(stages[i]);
-      const std::string current_line = std::to_string(std::get<1>(stages[i]));
-      error_message += current_filename.str() + ":" + current_line +
-                       ": error: '#pragma': conflicting stages for "
-                       "'shader_stage' #pragma: '" +
-                       current_stage.str() + "' (was '" +
-                       first_pragma_stage.str() + "' at " +
-                       first_pragma_filename.str() + ":" + first_pragma_line +
-                       ")\n";
+      ++num_conflicts;
+      if (num_conflicts <= kMaxReportedConflicts) {
+        const string_piece& current_filename = std::get<0>(stages[i]);
+        const std::string current_line = std::to_string(std::get<1>(stages[i]));
+        error_message += current_filename.str() + ":" + current_line +
+                         ": error: '#pragma': conflicting stages for "
+                         "'shader_stage' #pragma: '" +
+                         current_stage.str() + "' (was '" +
+                         first_pragma_stage.str() + "' at " +
+                         first_pragma_filename.str() + ":" + first_pragma_line +
+                         ")\n";
+      }
     }
   }
+  if (num_conflicts > kMaxReportedConflicts) {
+    error_message += "error: ... " +
+                     std::to_string(num_conflicts - kMaxReportedConflicts) +
+                     " more conflicting 'shader_stage' pragmas\n";
+  }
 
   return std::make_pair(error_message.empty() ? stage : EShLangCount,
                         error_message);