Redesign layout qualifier parsing to be simpler and more storage efficient.

TRAC #23268

Signed-off-by: Geoff Lang
Signed-off-by: Nicolas Capens
Authored-by: Jamie Madill
diff --git a/src/compiler/BaseTypes.h b/src/compiler/BaseTypes.h
index 3cb1efb..9d3811d 100644
--- a/src/compiler/BaseTypes.h
+++ b/src/compiler/BaseTypes.h
@@ -133,25 +133,38 @@
     EvqLast
 };
 
-// Layout qualifiers
-enum TLayoutQualifierType
+enum TLayoutMatrixPacking
 {
-    ElqLocation,
-    ElqShared,
-    ElqPacked,
-    ElqStd140,
-    ElqRowMajor,
-    ElqColumnMajor,
-    ElqError
+    EmpUnspecified,
+    EmpRowMajor,
+    EmpColumnMajor
 };
 
-struct TLayoutQualifierId
+enum TLayoutBlockStorage
 {
-    TLayoutQualifierType type;
+    EbsUnspecified,
+    EbsShared,
+    EbsPacked,
+    EbsStd140
+};
+
+struct TLayoutQualifier
+{
     int location;
-};
+    TLayoutMatrixPacking matrixPacking;
+    TLayoutBlockStorage blockStorage;
 
-typedef std::vector<TLayoutQualifierId> TLayoutQualifier;
+    static TLayoutQualifier create()
+    {
+        TLayoutQualifier layoutQualifier;
+
+        layoutQualifier.location = -1;
+        layoutQualifier.matrixPacking = EmpUnspecified;
+        layoutQualifier.blockStorage = EbsUnspecified;
+
+        return layoutQualifier;
+    }
+};
 
 //
 // This is just for debug print out, carried along with the definitions above.
@@ -193,6 +206,29 @@
     }
 }
 
+inline const char* getMatrixPackingString(TLayoutMatrixPacking mpq)
+{
+    switch (mpq)
+    {
+    case EmpUnspecified:    return "mp_unspecified";
+    case EmpRowMajor:       return "row_major";
+    case EmpColumnMajor:    return "column_major";
+    default:                return "unknown matrix packing";
+    }
+}
+
+inline const char* getBlockStorageString(TLayoutBlockStorage bsq)
+{
+    switch (bsq)
+    {
+    case EbsUnspecified:    return "bs_unspecified";
+    case EbsShared:         return "shared";
+    case EbsPacked:         return "packed";
+    case EbsStd140:         return "std140";
+    default:                return "unknown block storage";
+    }
+}
+
 inline const char* getInterpolationString(TQualifier q)
 {
     switch(q)
diff --git a/src/compiler/ParseHelper.cpp b/src/compiler/ParseHelper.cpp
index f79bbb8..ace297c 100644
--- a/src/compiler/ParseHelper.cpp
+++ b/src/compiler/ParseHelper.cpp
@@ -965,6 +965,45 @@
     return false;
 }
 
+bool TParseContext::singleDeclarationErrorCheck(TPublicType &publicType, TSourceLoc identifierLocation, const TString &identifier)
+{
+    if (structQualifierErrorCheck(identifierLocation, publicType))
+        return true;
+
+    // check for layout qualifier issues
+    const TLayoutQualifier layoutQualifier = publicType.layoutQualifier;
+
+    if (layoutQualifier.matrixPacking != EmpUnspecified)
+    {
+        error(identifierLocation, "layout qualifier", getMatrixPackingString(layoutQualifier.matrixPacking), "only valid for interface blocks");
+        return false;
+    }
+
+    if (layoutQualifier.blockStorage != EbsUnspecified)
+    {
+        error(identifierLocation, "layout qualifier", getBlockStorageString(layoutQualifier.blockStorage), "only valid for interface blocks");
+        return false;
+    }
+
+    if (publicType.qualifier != EvqVertexInput && publicType.qualifier != EvqFragmentOutput && layoutLocationErrorCheck(identifierLocation, publicType.layoutQualifier))
+    {
+        return false;
+    }
+
+    return false;
+}
+
+bool TParseContext::layoutLocationErrorCheck(TSourceLoc location, const TLayoutQualifier &layoutQualifier)
+{
+    if (layoutQualifier.location != -1)
+    {
+        error(location, "invalid layout qualifier:", "location", "only valid on program inputs and outputs");
+        return true;
+    }
+
+    return false;
+}
+
 bool TParseContext::supportsExtension(const char* extension)
 {
     const TExtensionBehavior& extbehavior = extensionBehavior();
@@ -1130,10 +1169,11 @@
     return allConstant;
 }
 
-TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, const TPublicType& typeSpecifier)
+TPublicType TParseContext::addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier)
 {
     TPublicType returnType = typeSpecifier;
     returnType.qualifier = qualifier;
+    returnType.layoutQualifier = layoutQualifier;
 
     if (typeSpecifier.array)
     {
@@ -1250,7 +1290,7 @@
 
 TIntermAggregate* TParseContext::parseSingleInitDeclaration(TPublicType &publicType, TSourceLoc identifierLocation, const TString &identifier, TSourceLoc initLocation, TIntermTyped *initializer)
 {
-    if (structQualifierErrorCheck(identifierLocation, publicType))
+    if (singleDeclarationErrorCheck(publicType, identifierLocation, identifier))
         recover();
 
     TIntermNode* intermNode;
@@ -1719,6 +1759,12 @@
         recover();
     }
 
+    const TLayoutQualifier layoutQualifier = typeQualifier.layoutQualifier;
+    if (layoutLocationErrorCheck(typeQualifier.line, layoutQualifier))
+    {
+        recover();
+    }
+
     TSymbol* blockNameSymbol = new TInterfaceBlockName(&blockName);
     if (!symbolTable.declare(*blockNameSymbol)) {
         error(nameLine, "redefinition", blockName.c_str(), "interface block name");
@@ -1745,11 +1791,18 @@
             recover();
             break;
         }
+
+        // check layout qualifiers
+        if (layoutLocationErrorCheck(memberTypeLine.line, memberType->getLayoutQualifier()))
+        {
+            recover();
+        }
     }
 
     TType* interfaceBlock = new TType(typeList, blockName);
     interfaceBlock->setBasicType(EbtInterfaceBlock);
     interfaceBlock->setQualifier(typeQualifier.qualifier);
+    interfaceBlock->setLayoutQualifier(layoutQualifier);
 
     TString symbolName = "";
     int symbolId = 0;
@@ -2182,32 +2235,33 @@
     return indexedExpression;
 }
 
-TLayoutQualifierId TParseContext::addLayoutQualifierId(const TString &qualifierType, TSourceLoc qualifierTypeLine)
+TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, TSourceLoc qualifierTypeLine)
 {
-    TLayoutQualifierId qualifierId;
+    TLayoutQualifier qualifier;
 
-    qualifierId.type = ElqError;
-    qualifierId.location = -1;
+    qualifier.location = -1;
+    qualifier.matrixPacking = EmpUnspecified;
+    qualifier.blockStorage = EbsUnspecified;
 
     if (qualifierType == "shared")
     {
-        qualifierId.type = ElqShared;
+        qualifier.blockStorage = EbsShared;
     }
     else if (qualifierType == "packed")
     {
-        qualifierId.type = ElqPacked;
+        qualifier.blockStorage = EbsPacked;
     }
     else if (qualifierType == "std140")
     {
-        qualifierId.type = ElqStd140;
+        qualifier.blockStorage = EbsStd140;
     }
     else if (qualifierType == "row_major")
     {
-        qualifierId.type = ElqRowMajor;
+        qualifier.matrixPacking = EmpRowMajor;
     }
     else if (qualifierType == "column_major")
     {
-        qualifierId.type = ElqColumnMajor;
+        qualifier.matrixPacking = EmpColumnMajor;
     }
     else if (qualifierType == "location")
     {
@@ -2220,15 +2274,16 @@
         recover();
     }
 
-    return qualifierId;
+    return qualifier;
 }
 
-TLayoutQualifierId TParseContext::addLayoutQualifierId(const TString &qualifierType, TSourceLoc qualifierTypeLine, const TString &intValueString, int intValue, TSourceLoc intValueLine)
+TLayoutQualifier TParseContext::parseLayoutQualifier(const TString &qualifierType, TSourceLoc qualifierTypeLine, const TString &intValueString, int intValue, TSourceLoc intValueLine)
 {
-    TLayoutQualifierId qualifierId;
+    TLayoutQualifier qualifier;
 
-    qualifierId.type = ElqError;
-    qualifierId.location = -1;
+    qualifier.location = -1;
+    qualifier.matrixPacking = EmpUnspecified;
+    qualifier.blockStorage = EbsUnspecified;
 
     if (qualifierType != "location")
     {
@@ -2244,23 +2299,33 @@
         }
         else
         {
-            qualifierId.location = intValue;
+            qualifier.location = intValue;
         }
 
         // TODO: must check that location is < MAX_DRAW_BUFFERS
     }
 
-    return qualifierId;
+    return qualifier;
 }
 
-TLayoutQualifier* TParseContext::makeLayoutQualifierFromId(TLayoutQualifierId layoutQualifierId)
+TLayoutQualifier TParseContext::joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier)
 {
-    return NULL;
-}
+    TLayoutQualifier joinedQualifier = leftQualifier;
 
-TLayoutQualifier* TParseContext::extendLayoutQualifier(TLayoutQualifier *layoutQualifier, TLayoutQualifierId layoutQualifierId)
-{
-    return NULL;
+    if (rightQualifier.location != -1)
+    {
+        joinedQualifier.location = rightQualifier.location;
+    }
+    if (rightQualifier.matrixPacking != EmpUnspecified)
+    {
+        joinedQualifier.matrixPacking = rightQualifier.matrixPacking;
+    }
+    if (rightQualifier.blockStorage != EbsUnspecified)
+    {
+        joinedQualifier.blockStorage = rightQualifier.blockStorage;
+    }
+
+    return joinedQualifier;
 }
 
 TTypeList *TParseContext::addStructDeclaratorList(const TPublicType& typeSpecifier, TTypeList *typeList)
@@ -2279,6 +2344,7 @@
         type->setSecondarySize(typeSpecifier.secondarySize);
         type->setPrecision(typeSpecifier.precision);
         type->setQualifier(typeSpecifier.qualifier);
+        type->setLayoutQualifier(typeSpecifier.layoutQualifier);
 
         // don't allow arrays of arrays
         if (type->isArray()) {
diff --git a/src/compiler/ParseHelper.h b/src/compiler/ParseHelper.h
index 4a0f2d5..d184e26 100644
--- a/src/compiler/ParseHelper.h
+++ b/src/compiler/ParseHelper.h
@@ -100,6 +100,8 @@
     bool nonInitErrorCheck(int line, const TString& identifier, const TPublicType& type, TVariable*& variable);
     bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type);
     bool extensionErrorCheck(int line, const TString&);
+    bool singleDeclarationErrorCheck(TPublicType &publicType, TSourceLoc identifierLocation, const TString &identifier);
+    bool layoutLocationErrorCheck(TSourceLoc location, const TLayoutQualifier &layoutQualifier);
 
     const TExtensionBehavior& extensionBehavior() const { return directiveHandler.extensionBehavior(); }
     bool supportsExtension(const char* extension);
@@ -116,6 +118,7 @@
     bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc);
 
     TPublicType addFullySpecifiedType(TQualifier qualifier, const TPublicType& typeSpecifier);
+    TPublicType addFullySpecifiedType(TQualifier qualifier, TLayoutQualifier layoutQualifier, const TPublicType& typeSpecifier);
     TIntermAggregate* parseSingleDeclaration(TPublicType &publicType, TSourceLoc identifierLocation, const TString &identifier);
     TIntermAggregate* parseSingleArrayDeclaration(TPublicType &publicType, TSourceLoc identifierLocation, const TString &identifier, TSourceLoc indexLocation, TIntermTyped *indexExpression);
     TIntermAggregate* parseSingleInitDeclaration(TPublicType &publicType, TSourceLoc identifierLocation, const TString &identifier, TSourceLoc initLocation, TIntermTyped *initializer);
@@ -137,10 +140,9 @@
     TIntermAggregate* addInterfaceBlock(const TPublicType& typeQualifier, TSourceLoc nameLine, const TString& blockName, TTypeList* typeList, 
                                         const TString& instanceName, TSourceLoc instanceLine, TIntermTyped* arrayIndex, TSourceLoc arrayIndexLine);
 
-    TLayoutQualifierId addLayoutQualifierId(const TString &qualifierType, TSourceLoc qualifierTypeLine);
-    TLayoutQualifierId addLayoutQualifierId(const TString &qualifierType, TSourceLoc qualifierTypeLine, const TString &intValueString, int intValue, TSourceLoc intValueLine);
-    TLayoutQualifier* makeLayoutQualifierFromId(TLayoutQualifierId layoutQualifierId);
-    TLayoutQualifier* extendLayoutQualifier(TLayoutQualifier *layoutQualifier, TLayoutQualifierId layoutQualifierId);
+    TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, TSourceLoc qualifierTypeLine);
+    TLayoutQualifier parseLayoutQualifier(const TString &qualifierType, TSourceLoc qualifierTypeLine, const TString &intValueString, int intValue, TSourceLoc intValueLine);
+    TLayoutQualifier joinLayoutQualifiers(TLayoutQualifier leftQualifier, TLayoutQualifier rightQualifier);
 
     // Performs an error check for embedded struct declarations.
     // Returns true if an error was raised due to the declaration of
diff --git a/src/compiler/SymbolTable.cpp b/src/compiler/SymbolTable.cpp
index d9f3ed3..c9c6291 100644
--- a/src/compiler/SymbolTable.cpp
+++ b/src/compiler/SymbolTable.cpp
@@ -21,7 +21,7 @@
 #include "common/angleutils.h"
 
 TType::TType(const TPublicType &p) :
-            type(p.type), precision(p.precision), qualifier(p.qualifier), primarySize(p.primarySize), secondarySize(p.secondarySize), array(p.array), arraySize(p.arraySize),
+            type(p.type), precision(p.precision), qualifier(p.qualifier), primarySize(p.primarySize), secondarySize(p.secondarySize), array(p.array), layoutQualifier(p.layoutQualifier), arraySize(p.arraySize),
             maxArraySize(0), arrayInformationType(0), interfaceBlockType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0)
 {
     if (p.userDef) {
diff --git a/src/compiler/Types.h b/src/compiler/Types.h
index 0e892ab..cd23e1f 100644
--- a/src/compiler/Types.h
+++ b/src/compiler/Types.h
@@ -38,13 +38,13 @@
     POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator)
     TType() {}
     TType(TBasicType t, TPrecision p, TQualifier q = EvqTemporary, int ps = 1, int ss = 1, bool a = false) :
-            type(t), precision(p), qualifier(q), primarySize(ps), secondarySize(ss), array(a), arraySize(0),
+            type(t), precision(p), qualifier(q), primarySize(ps), secondarySize(ss), array(a), layoutQualifier(TLayoutQualifier::create()), arraySize(0),
             maxArraySize(0), arrayInformationType(0), interfaceBlockType(0), structure(0), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), typeName(0), instanceName(0)
     {
     }
     explicit TType(const TPublicType &p);
     TType(TTypeList* userDef, const TString& n, TPrecision p = EbpUndefined) :
-            type(EbtStruct), precision(p), qualifier(EvqTemporary), primarySize(1), secondarySize(1), array(false), arraySize(0),
+            type(EbtStruct), precision(p), qualifier(EvqTemporary), primarySize(1), secondarySize(1), array(false), layoutQualifier(TLayoutQualifier::create()), arraySize(0),
             maxArraySize(0), arrayInformationType(0), interfaceBlockType(0), structure(userDef), structureSize(0), deepestStructNesting(0), fieldName(0), mangled(0), instanceName(0)
     {
         typeName = NewPoolTString(n.c_str());
@@ -59,6 +59,9 @@
     TQualifier getQualifier() const { return qualifier; }
     void setQualifier(TQualifier q) { qualifier = q; }
 
+    TLayoutQualifier getLayoutQualifier() const { return layoutQualifier; }
+    void setLayoutQualifier(TLayoutQualifier lq) { layoutQualifier = lq; }
+
     int getNominalSize() const { return primarySize; }
     int getSecondarySize() const { return secondarySize; }
     int getCols() const { ASSERT(isMatrix()); return primarySize; }
@@ -247,6 +250,7 @@
     TPrecision precision : 4;
     TQualifier qualifier : 7;
     unsigned int array   : 1;
+    TLayoutQualifier layoutQualifier;
     int primarySize; // size of vector or cols matrix
     int secondarySize; // rows of a matrix
     int arraySize;
@@ -276,7 +280,7 @@
 struct TPublicType
 {
     TBasicType type;
-    TLayoutQualifier* layoutQualifier;
+    TLayoutQualifier layoutQualifier;
     TQualifier qualifier;
     TPrecision precision;
     int primarySize;          // size of vector or cols of matrix
@@ -289,7 +293,7 @@
     void setBasic(TBasicType bt, TQualifier q, int ln = 0)
     {
         type = bt;
-        layoutQualifier = NULL;
+        layoutQualifier = TLayoutQualifier::create();
         qualifier = q;
         precision = EbpUndefined;
         primarySize = 1;
diff --git a/src/compiler/glslang.y b/src/compiler/glslang.y
index f9713c2..d27a87d 100644
--- a/src/compiler/glslang.y
+++ b/src/compiler/glslang.y
@@ -72,8 +72,7 @@
         union {
             TPublicType type;
             TPrecision precision;
-            TLayoutQualifierId layoutQualifierId;
-            TLayoutQualifier* layoutQualifier;
+            TLayoutQualifier layoutQualifier;
             TQualifier qualifier;
             TFunction* function;
             TParameter param;
@@ -171,8 +170,7 @@
 
 %type <interm> parameter_declaration parameter_declarator parameter_type_specifier
 %type <interm.qualifier> parameter_qualifier parameter_type_qualifier 
-%type <interm.layoutQualifier> layout_qualifier layout_qualifier_id_list
-%type <interm.layoutQualifierId> layout_qualifier_id
+%type <interm.layoutQualifier> layout_qualifier layout_qualifier_id_list layout_qualifier_id
 
 %type <interm.precision> precision_qualifier
 %type <interm.type> type_qualifier fully_specified_type type_specifier storage_qualifier interpolation_qualifier
@@ -1220,7 +1218,7 @@
         }
     }
     | type_qualifier type_specifier  {
-        $$ = context->addFullySpecifiedType($1.qualifier, $2);
+        $$ = context->addFullySpecifiedType($1.qualifier, $1.layoutQualifier, $2);
     }
     ;
 
@@ -1404,22 +1402,22 @@
 
 layout_qualifier_id_list
     : layout_qualifier_id {
-        $$ = context->makeLayoutQualifierFromId($1);
+        $$ = $1;
     }
     | layout_qualifier_id_list COMMA layout_qualifier_id {
-        $$ = context->extendLayoutQualifier($1, $3);
+        $$ = context->joinLayoutQualifiers($1, $3);
     }
     ;
 
 layout_qualifier_id
     : IDENTIFIER {
-        $$ = context->addLayoutQualifierId(*$1.string, $1.line);
+        $$ = context->parseLayoutQualifier(*$1.string, $1.line);
     }
     | IDENTIFIER EQUAL INTCONSTANT {
-        $$ = context->addLayoutQualifierId(*$1.string, $1.line, *$3.string, $3.i, $3.line);
+        $$ = context->parseLayoutQualifier(*$1.string, $1.line, *$3.string, $3.i, $3.line);
     }
     | IDENTIFIER EQUAL UINTCONSTANT {
-        $$ = context->addLayoutQualifierId(*$1.string, $1.line, *$3.string, $3.i, $3.line);
+        $$ = context->parseLayoutQualifier(*$1.string, $1.line, *$3.string, $3.i, $3.line);
     }
     ;
 
@@ -1649,6 +1647,7 @@
     | type_qualifier type_specifier struct_declarator_list SEMICOLON {
         // ES3 Only, but errors should be handled elsewhere
         $2.qualifier = $1.qualifier;
+        $2.layoutQualifier = $1.layoutQualifier;
         $$ = context->addStructDeclaratorList($2, $3);
     }
     ;
diff --git a/src/compiler/glslang_tab.cpp b/src/compiler/glslang_tab.cpp
index f60364d..607e79d 100644
--- a/src/compiler/glslang_tab.cpp
+++ b/src/compiler/glslang_tab.cpp
@@ -276,8 +276,7 @@
         union {
             TPublicType type;
             TPrecision precision;
-            TLayoutQualifierId layoutQualifierId;
-            TLayoutQualifier* layoutQualifier;
+            TLayoutQualifier layoutQualifier;
             TQualifier qualifier;
             TFunction* function;
             TParameter param;
@@ -741,30 +740,30 @@
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   194,   194,   195,   198,   233,   236,   241,   246,   251,
-     256,   262,   265,   268,   271,   274,   284,   297,   305,   405,
-     408,   416,   420,   427,   431,   438,   444,   453,   461,   464,
-     474,   477,   487,   497,   518,   519,   520,   525,   526,   535,
-     547,   548,   556,   567,   571,   572,   582,   592,   602,   615,
-     616,   626,   639,   643,   647,   651,   652,   665,   666,   679,
-     680,   693,   694,   711,   712,   725,   726,   727,   728,   729,
-     733,   736,   747,   755,   763,   790,   795,   806,   810,   814,
-     821,   859,   862,   869,   877,   898,   919,   930,   959,   964,
-     974,   979,   989,   992,   995,   998,  1004,  1011,  1014,  1036,
-    1054,  1078,  1101,  1105,  1109,  1116,  1120,  1124,  1213,  1222,
-    1228,  1232,  1239,  1245,  1252,  1261,  1270,  1273,  1309,  1316,
-    1320,  1327,  1331,  1336,  1341,  1351,  1361,  1370,  1380,  1387,
-    1390,  1393,  1399,  1406,  1409,  1415,  1418,  1421,  1427,  1430,
-    1445,  1449,  1453,  1457,  1461,  1465,  1470,  1475,  1480,  1485,
-    1490,  1495,  1500,  1505,  1510,  1515,  1520,  1525,  1531,  1537,
-    1543,  1548,  1553,  1558,  1563,  1568,  1573,  1578,  1583,  1592,
-    1601,  1606,  1619,  1619,  1622,  1622,  1628,  1631,  1646,  1649,
-    1657,  1661,  1667,  1675,  1691,  1695,  1699,  1700,  1706,  1707,
-    1708,  1709,  1710,  1714,  1715,  1715,  1715,  1725,  1726,  1730,
-    1730,  1731,  1731,  1736,  1739,  1749,  1752,  1758,  1759,  1763,
-    1771,  1775,  1785,  1790,  1807,  1807,  1812,  1812,  1819,  1819,
-    1827,  1830,  1836,  1839,  1845,  1849,  1856,  1863,  1870,  1877,
-    1888,  1897,  1901,  1908,  1911,  1917,  1917
+       0,   192,   192,   193,   196,   231,   234,   239,   244,   249,
+     254,   260,   263,   266,   269,   272,   282,   295,   303,   403,
+     406,   414,   418,   425,   429,   436,   442,   451,   459,   462,
+     472,   475,   485,   495,   516,   517,   518,   523,   524,   533,
+     545,   546,   554,   565,   569,   570,   580,   590,   600,   613,
+     614,   624,   637,   641,   645,   649,   650,   663,   664,   677,
+     678,   691,   692,   709,   710,   723,   724,   725,   726,   727,
+     731,   734,   745,   753,   761,   788,   793,   804,   808,   812,
+     819,   857,   860,   867,   875,   896,   917,   928,   957,   962,
+     972,   977,   987,   990,   993,   996,  1002,  1009,  1012,  1034,
+    1052,  1076,  1099,  1103,  1107,  1114,  1118,  1122,  1211,  1220,
+    1226,  1230,  1237,  1243,  1250,  1259,  1268,  1271,  1307,  1314,
+    1318,  1325,  1329,  1334,  1339,  1349,  1359,  1368,  1378,  1385,
+    1388,  1391,  1397,  1404,  1407,  1413,  1416,  1419,  1425,  1428,
+    1443,  1447,  1451,  1455,  1459,  1463,  1468,  1473,  1478,  1483,
+    1488,  1493,  1498,  1503,  1508,  1513,  1518,  1523,  1529,  1535,
+    1541,  1546,  1551,  1556,  1561,  1566,  1571,  1576,  1581,  1590,
+    1599,  1604,  1617,  1617,  1620,  1620,  1626,  1629,  1644,  1647,
+    1656,  1660,  1666,  1674,  1690,  1694,  1698,  1699,  1705,  1706,
+    1707,  1708,  1709,  1713,  1714,  1714,  1714,  1724,  1725,  1729,
+    1729,  1730,  1730,  1735,  1738,  1748,  1751,  1757,  1758,  1762,
+    1770,  1774,  1784,  1789,  1806,  1806,  1811,  1811,  1818,  1818,
+    1826,  1829,  1835,  1838,  1844,  1848,  1855,  1862,  1869,  1876,
+    1887,  1896,  1900,  1907,  1910,  1916,  1916
 };
 #endif
 
@@ -3547,7 +3546,7 @@
   case 109:
 
     {
-        (yyval.interm.type) = context->addFullySpecifiedType((yyvsp[(1) - (2)].interm.type).qualifier, (yyvsp[(2) - (2)].interm.type));
+        (yyval.interm.type) = context->addFullySpecifiedType((yyvsp[(1) - (2)].interm.type).qualifier, (yyvsp[(1) - (2)].interm.type).layoutQualifier, (yyvsp[(2) - (2)].interm.type));
     }
     break;
 
@@ -3803,35 +3802,35 @@
   case 133:
 
     {
-        (yyval.interm.layoutQualifier) = context->makeLayoutQualifierFromId((yyvsp[(1) - (1)].interm.layoutQualifierId));
+        (yyval.interm.layoutQualifier) = (yyvsp[(1) - (1)].interm.layoutQualifier);
     }
     break;
 
   case 134:
 
     {
-        (yyval.interm.layoutQualifier) = context->extendLayoutQualifier((yyvsp[(1) - (3)].interm.layoutQualifier), (yyvsp[(3) - (3)].interm.layoutQualifierId));
+        (yyval.interm.layoutQualifier) = context->joinLayoutQualifiers((yyvsp[(1) - (3)].interm.layoutQualifier), (yyvsp[(3) - (3)].interm.layoutQualifier));
     }
     break;
 
   case 135:
 
     {
-        (yyval.interm.layoutQualifierId) = context->addLayoutQualifierId(*(yyvsp[(1) - (1)].lex).string, (yyvsp[(1) - (1)].lex).line);
+        (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[(1) - (1)].lex).string, (yyvsp[(1) - (1)].lex).line);
     }
     break;
 
   case 136:
 
     {
-        (yyval.interm.layoutQualifierId) = context->addLayoutQualifierId(*(yyvsp[(1) - (3)].lex).string, (yyvsp[(1) - (3)].lex).line, *(yyvsp[(3) - (3)].lex).string, (yyvsp[(3) - (3)].lex).i, (yyvsp[(3) - (3)].lex).line);
+        (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[(1) - (3)].lex).string, (yyvsp[(1) - (3)].lex).line, *(yyvsp[(3) - (3)].lex).string, (yyvsp[(3) - (3)].lex).i, (yyvsp[(3) - (3)].lex).line);
     }
     break;
 
   case 137:
 
     {
-        (yyval.interm.layoutQualifierId) = context->addLayoutQualifierId(*(yyvsp[(1) - (3)].lex).string, (yyvsp[(1) - (3)].lex).line, *(yyvsp[(3) - (3)].lex).string, (yyvsp[(3) - (3)].lex).i, (yyvsp[(3) - (3)].lex).line);
+        (yyval.interm.layoutQualifier) = context->parseLayoutQualifier(*(yyvsp[(1) - (3)].lex).string, (yyvsp[(1) - (3)].lex).line, *(yyvsp[(3) - (3)].lex).string, (yyvsp[(3) - (3)].lex).i, (yyvsp[(3) - (3)].lex).line);
     }
     break;
 
@@ -4216,6 +4215,7 @@
     {
         // ES3 Only, but errors should be handled elsewhere
         (yyvsp[(2) - (4)].interm.type).qualifier = (yyvsp[(1) - (4)].interm.type).qualifier;
+        (yyvsp[(2) - (4)].interm.type).layoutQualifier = (yyvsp[(1) - (4)].interm.type).layoutQualifier;
         (yyval.interm.typeList) = context->addStructDeclaratorList((yyvsp[(2) - (4)].interm.type), (yyvsp[(3) - (4)].interm.typeList));
     }
     break;
diff --git a/src/compiler/glslang_tab.h b/src/compiler/glslang_tab.h
index ef0c0fa..1fdd332 100644
--- a/src/compiler/glslang_tab.h
+++ b/src/compiler/glslang_tab.h
@@ -192,8 +192,7 @@
         union {
             TPublicType type;
             TPrecision precision;
-            TLayoutQualifierId layoutQualifierId;
-            TLayoutQualifier* layoutQualifier;
+            TLayoutQualifier layoutQualifier;
             TQualifier qualifier;
             TFunction* function;
             TParameter param;