Fix detecting duplicate field names in structures

Previously field names that were listed in the first declarator list
inside a struct declaration were not checked against each other.

BUG=angleproject:2204
TEST=angle_unittests

Change-Id: Ibf821d45556f6dfe0223dae673644f6795daf4cb
Reviewed-on: https://chromium-review.googlesource.com/739825
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
diff --git a/src/compiler/translator/ParseContext.cpp b/src/compiler/translator/ParseContext.cpp
index 3f0ce5a..15a9cd6 100644
--- a/src/compiler/translator/ParseContext.cpp
+++ b/src/compiler/translator/ParseContext.cpp
@@ -4573,19 +4573,39 @@
     return new TField(type, identifier, loc);
 }
 
+void TParseContext::checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin,
+                                                       const TFieldList::const_iterator end,
+                                                       const TString &name,
+                                                       const TSourceLoc &location)
+{
+    for (auto fieldIter = begin; fieldIter != end; ++fieldIter)
+    {
+        if ((*fieldIter)->name() == name)
+        {
+            error(location, "duplicate field name in structure", name.c_str());
+        }
+    }
+}
+
+TFieldList *TParseContext::addStructFieldList(TFieldList *fields, const TSourceLoc &location)
+{
+    for (TFieldList::const_iterator fieldIter = fields->begin(); fieldIter != fields->end();
+         ++fieldIter)
+    {
+        checkDoesNotHaveDuplicateFieldName(fields->begin(), fieldIter, (*fieldIter)->name(),
+                                           location);
+    }
+    return fields;
+}
+
 TFieldList *TParseContext::combineStructFieldLists(TFieldList *processedFields,
                                                    const TFieldList *newlyAddedFields,
                                                    const TSourceLoc &location)
 {
     for (TField *field : *newlyAddedFields)
     {
-        for (TField *oldField : *processedFields)
-        {
-            if (oldField->name() == field->name())
-            {
-                error(location, "duplicate field name in structure", field->name().c_str());
-            }
-        }
+        checkDoesNotHaveDuplicateFieldName(processedFields->begin(), processedFields->end(),
+                                           field->name(), location);
         processedFields->push_back(field);
     }
     return processedFields;
diff --git a/src/compiler/translator/ParseContext.h b/src/compiler/translator/ParseContext.h
index f423b83..1f7f5b9 100644
--- a/src/compiler/translator/ParseContext.h
+++ b/src/compiler/translator/ParseContext.h
@@ -306,6 +306,11 @@
                                        unsigned int arraySize,
                                        const TSourceLoc &arraySizeLoc);
 
+    void checkDoesNotHaveDuplicateFieldName(const TFieldList::const_iterator begin,
+                                            const TFieldList::const_iterator end,
+                                            const TString &name,
+                                            const TSourceLoc &location);
+    TFieldList *addStructFieldList(TFieldList *fields, const TSourceLoc &location);
     TFieldList *combineStructFieldLists(TFieldList *processedFields,
                                         const TFieldList *newlyAddedFields,
                                         const TSourceLoc &location);
diff --git a/src/compiler/translator/glslang.y b/src/compiler/translator/glslang.y
index 98f313b..b02710b 100644
--- a/src/compiler/translator/glslang.y
+++ b/src/compiler/translator/glslang.y
@@ -1187,7 +1187,7 @@
 
 struct_declaration_list
     : struct_declaration {
-        $$ = $1;
+        $$ = context->addStructFieldList($1, @1);
     }
     | struct_declaration_list struct_declaration {
         $$ = context->combineStructFieldLists($1, $2, @2);
diff --git a/src/compiler/translator/glslang_tab.cpp b/src/compiler/translator/glslang_tab.cpp
index ea56b37..64fac5a 100644
--- a/src/compiler/translator/glslang_tab.cpp
+++ b/src/compiler/translator/glslang_tab.cpp
@@ -4358,7 +4358,7 @@
   case 229:
 
     {
-        (yyval.interm.fieldList) = (yyvsp[0].interm.fieldList);
+        (yyval.interm.fieldList) = context->addStructFieldList((yyvsp[0].interm.fieldList), (yylsp[0]));
     }
 
     break;
diff --git a/src/tests/compiler_tests/ShaderValidation_test.cpp b/src/tests/compiler_tests/ShaderValidation_test.cpp
index 61a6945..51b793b 100644
--- a/src/tests/compiler_tests/ShaderValidation_test.cpp
+++ b/src/tests/compiler_tests/ShaderValidation_test.cpp
@@ -5172,4 +5172,25 @@
     {
         FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
     }
-}
\ No newline at end of file
+}
+
+// Test that duplicate field names in a struct declarator list are validated.
+TEST_F(FragmentShaderValidationTest, DuplicateFieldNamesInStructDeclaratorList)
+{
+    const std::string &shaderString =
+        R"(precision mediump float;
+
+        struct S {
+            float f, f;
+        };
+
+        void main()
+        {
+            gl_FragColor = vec4(1.0);
+        })";
+
+    if (compile(shaderString))
+    {
+        FAIL() << "Shader compilation succeeded, expecting failure:\n" << mInfoLog;
+    }
+}