Imported a few ES3 fixes from Angle

Imported some of the more trivial bug fixes:
- Added a few missing interface block cases
- Added checks for varying structs
- Added checks for unsized arrays
- Added first-class array check for pre ES3 compilation
- Added check that ES3 functions do not use builtin names (ES3 only)
- Added more binary operator checks

Change-Id: I3d75453f17e1123478ef7da0998e869970a7fb7d
Reviewed-on: https://swiftshader-review.googlesource.com/8289
Tested-by: Alexis Hétu <sugoi@google.com>
Reviewed-by: Nicolas Capens <capn@google.com>
diff --git a/src/OpenGL/compiler/Intermediate.cpp b/src/OpenGL/compiler/Intermediate.cpp
index dbbfb19..a6b1b82 100644
--- a/src/OpenGL/compiler/Intermediate.cpp
+++ b/src/OpenGL/compiler/Intermediate.cpp
@@ -62,6 +62,134 @@
 	}
 }
 
+TOperator TypeToConstructorOperator(const TType &type)
+{
+	switch(type.getBasicType())
+	{
+	case EbtFloat:
+		if(type.isMatrix())
+		{
+			switch(type.getNominalSize())
+			{
+			case 2:
+				switch(type.getSecondarySize())
+				{
+				case 2:
+					return EOpConstructMat2;
+				case 3:
+					return EOpConstructMat2x3;
+				case 4:
+					return EOpConstructMat2x4;
+				default:
+					break;
+				}
+				break;
+
+			case 3:
+				switch(type.getSecondarySize())
+				{
+				case 2:
+					return EOpConstructMat3x2;
+				case 3:
+					return EOpConstructMat3;
+				case 4:
+					return EOpConstructMat3x4;
+				default:
+					break;
+				}
+				break;
+
+			case 4:
+				switch(type.getSecondarySize())
+				{
+				case 2:
+					return EOpConstructMat4x2;
+				case 3:
+					return EOpConstructMat4x3;
+				case 4:
+					return EOpConstructMat4;
+				default:
+					break;
+				}
+				break;
+			}
+		}
+		else
+		{
+			switch(type.getNominalSize())
+			{
+			case 1:
+				return EOpConstructFloat;
+			case 2:
+				return EOpConstructVec2;
+			case 3:
+				return EOpConstructVec3;
+			case 4:
+				return EOpConstructVec4;
+			default:
+				break;
+			}
+		}
+		break;
+
+	case EbtInt:
+		switch(type.getNominalSize())
+		{
+		case 1:
+			return EOpConstructInt;
+		case 2:
+			return EOpConstructIVec2;
+		case 3:
+			return EOpConstructIVec3;
+		case 4:
+			return EOpConstructIVec4;
+		default:
+			break;
+		}
+		break;
+
+	case EbtUInt:
+		switch(type.getNominalSize())
+		{
+		case 1:
+			return EOpConstructUInt;
+		case 2:
+			return EOpConstructUVec2;
+		case 3:
+			return EOpConstructUVec3;
+		case 4:
+			return EOpConstructUVec4;
+		default:
+			break;
+		}
+		break;
+
+	case EbtBool:
+		switch(type.getNominalSize())
+		{
+		case 1:
+			return EOpConstructBool;
+		case 2:
+			return EOpConstructBVec2;
+		case 3:
+			return EOpConstructBVec3;
+		case 4:
+			return EOpConstructBVec4;
+		default:
+			break;
+		}
+		break;
+
+	case EbtStruct:
+		return EOpConstructStruct;
+
+	default:
+		break;
+	}
+
+	return EOpNull;
+}
+
 const char* getOperatorString(TOperator op) {
 	switch (op) {
 	case EOpInitialize: return "=";
@@ -657,6 +785,17 @@
 //
 ////////////////////////////////////////////////////////////////
 
+// static
+TIntermTyped *TIntermTyped::CreateIndexNode(int index)
+{
+	ConstantUnion *u = new ConstantUnion[1];
+	u[0].setIConst(index);
+
+	TType type(EbtInt, EbpUndefined, EvqConstExpr, 1);
+	TIntermConstantUnion *node = new TIntermConstantUnion(u, type);
+	return node;
+}
+
 //
 // Say whether or not an operation node changes the value of a variable.
 //
diff --git a/src/OpenGL/compiler/ParseHelper.cpp b/src/OpenGL/compiler/ParseHelper.cpp
index 7bd7e64..83f58ce 100644
--- a/src/OpenGL/compiler/ParseHelper.cpp
+++ b/src/OpenGL/compiler/ParseHelper.cpp
@@ -28,6 +28,77 @@
 //
 ////////////////////////////////////////////////////////////////////////
 
+namespace
+{
+	bool IsVaryingOut(TQualifier qualifier)
+	{
+		switch(qualifier)
+		{
+		case EvqVaryingOut:
+		case EvqSmoothOut:
+		case EvqFlatOut:
+		case EvqCentroidOut:
+		case EvqVertexOut:
+			return true;
+
+		default: break;
+		}
+
+		return false;
+	}
+
+	bool IsVaryingIn(TQualifier qualifier)
+	{
+		switch(qualifier)
+		{
+		case EvqVaryingIn:
+		case EvqSmoothIn:
+		case EvqFlatIn:
+		case EvqCentroidIn:
+		case EvqFragmentIn:
+			return true;
+
+		default: break;
+		}
+
+		return false;
+	}
+
+	bool IsVarying(TQualifier qualifier)
+	{
+		return IsVaryingIn(qualifier) || IsVaryingOut(qualifier);
+	}
+
+	bool IsAssignment(TOperator op)
+	{
+		switch(op)
+		{
+		case EOpPostIncrement:
+		case EOpPostDecrement:
+		case EOpPreIncrement:
+		case EOpPreDecrement:
+		case EOpAssign:
+		case EOpAddAssign:
+		case EOpSubAssign:
+		case EOpMulAssign:
+		case EOpVectorTimesMatrixAssign:
+		case EOpVectorTimesScalarAssign:
+		case EOpMatrixTimesScalarAssign:
+		case EOpMatrixTimesMatrixAssign:
+		case EOpDivAssign:
+		case EOpIModAssign:
+		case EOpBitShiftLeftAssign:
+		case EOpBitShiftRightAssign:
+		case EOpBitwiseAndAssign:
+		case EOpBitwiseXorAssign:
+		case EOpBitwiseOrAssign:
+			return true;
+		default:
+			return false;
+		}
+	}
+}
+
 //
 // Look at a '.' field selector string and change it into offsets
 // for a vector.
@@ -282,6 +353,7 @@
 		case EOpIndexDirect:
 		case EOpIndexIndirect:
 		case EOpIndexDirectStruct:
+		case EOpIndexDirectInterfaceBlock:
 			return lValueErrorCheck(line, op, binaryNode->getLeft());
 		case EOpVectorSwizzle:
 			errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft());
@@ -756,7 +828,7 @@
 	if (IsSampler(type.getBasicType()))
 		return true;
 
-	if (type.getBasicType() == EbtStruct) {
+	if (type.getBasicType() == EbtStruct || type.isInterfaceBlock()) {
 		const TFieldList& fields = type.getStruct()->fields();
 		for(unsigned int i = 0; i < fields.size(); ++i) {
 			if (containsSampler(*fields[i]->type()))
@@ -776,7 +848,7 @@
 {
 	TIntermConstantUnion* constant = expr->getAsConstantUnion();
 
-	if (constant == 0 || !constant->isScalarInt())
+	if (expr->getQualifier() != EvqConstExpr || constant == 0 || !constant->isScalarInt())
 	{
 		error(line, "array size must be a constant integer expression", "");
 		return true;
@@ -798,14 +870,20 @@
 	{
 		size = constant->getIConst(0);
 
-		if (size <= 0)
+		if (size < 0)
 		{
-			error(line, "array size must be a positive integer", "");
+			error(line, "array size must be non-negative", "");
 			size = 1;
 			return true;
 		}
 	}
 
+	if(size == 0)
+	{
+		error(line, "array size must be greater than zero", "");
+		return true;
+	}
+
 	return false;
 }
 
@@ -839,6 +917,15 @@
 		return true;
 	}
 
+	// In ESSL1.00 shaders, structs cannot be varying (section 4.3.5). This is checked elsewhere.
+	// In ESSL3.00 shaders, struct inputs/outputs are allowed but not arrays of structs (section 4.3.4).
+	if(mShaderVersion >= 300 && type.type == EbtStruct && IsVarying(type.qualifier))
+	{
+		error(line, "cannot declare arrays of structs of this qualifier",
+		      TType(type).getCompleteString().c_str());
+		return true;
+	}
+
 	return false;
 }
 
@@ -1191,9 +1278,19 @@
 	ASSERT(intermNode != nullptr);
 	TType type = TType(pType);
 
-	if(type.isArray() && (type.getArraySize() == 0))
+	if(type.isUnsizedArray())
 	{
-		type.setArraySize(initializer->getArraySize());
+		// We have not checked yet whether the initializer actually is an array or not.
+		if(initializer->isArray())
+		{
+			type.setArraySize(initializer->getArraySize());
+		}
+		else
+		{
+			// Having a non-array initializer for an unsized array will result in an error later,
+			// so we don't generate an error message here.
+			type.setArraySize(1u);
+		}
 	}
 
 	TVariable *variable = nullptr;
@@ -1285,6 +1382,12 @@
 
 	if(mShaderVersion < 300)
 	{
+		if(typeSpecifier.array)
+		{
+			error(typeSpecifier.line, "not supported", "first-class array");
+			returnType.clearArrayness();
+		}
+
 		if(qualifier == EvqAttribute && (typeSpecifier.type == EbtBool || typeSpecifier.type == EbtInt))
 		{
 			error(typeSpecifier.line, "cannot be bool or int", getQualifierString(qualifier));
@@ -1300,44 +1403,87 @@
 	}
 	else
 	{
-		switch(qualifier)
+		if(!returnType.layoutQualifier.isEmpty())
 		{
-		case EvqSmoothIn:
-		case EvqSmoothOut:
-		case EvqVertexOut:
-		case EvqFragmentIn:
-		case EvqCentroidOut:
-		case EvqCentroidIn:
-			if(typeSpecifier.type == EbtBool)
-			{
-				error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
-				recover();
-			}
-			if(typeSpecifier.type == EbtInt || typeSpecifier.type == EbtUInt)
-			{
-				error(typeSpecifier.line, "must use 'flat' interpolation here", getQualifierString(qualifier));
-				recover();
-			}
-			break;
+			globalErrorCheck(typeSpecifier.line, symbolTable.atGlobalLevel(), "layout");
+		}
 
-		case EvqVertexIn:
-		case EvqFragmentOut:
-		case EvqFlatIn:
-		case EvqFlatOut:
-			if(typeSpecifier.type == EbtBool)
-			{
-				error(typeSpecifier.line, "cannot be bool", getQualifierString(qualifier));
-				recover();
-			}
-			break;
-
-		default: break;
+		if(IsVarying(returnType.qualifier) || returnType.qualifier == EvqVertexIn || returnType.qualifier == EvqFragmentOut)
+		{
+			checkInputOutputTypeIsValidES3(returnType.qualifier, typeSpecifier, typeSpecifier.line);
 		}
 	}
 
 	return returnType;
 }
 
+void TParseContext::checkInputOutputTypeIsValidES3(const TQualifier qualifier,
+                                                   const TPublicType &type,
+                                                   const TSourceLoc &qualifierLocation)
+{
+	// An input/output variable can never be bool or a sampler. Samplers are checked elsewhere.
+	if(type.type == EbtBool)
+	{
+		error(qualifierLocation, "cannot be bool", getQualifierString(qualifier));
+	}
+
+	// Specific restrictions apply for vertex shader inputs and fragment shader outputs.
+	switch(qualifier)
+	{
+	case EvqVertexIn:
+		// ESSL 3.00 section 4.3.4
+		if(type.array)
+		{
+			error(qualifierLocation, "cannot be array", getQualifierString(qualifier));
+		}
+		// Vertex inputs with a struct type are disallowed in singleDeclarationErrorCheck
+		return;
+	case EvqFragmentOut:
+		// ESSL 3.00 section 4.3.6
+		if(type.isMatrix())
+		{
+			error(qualifierLocation, "cannot be matrix", getQualifierString(qualifier));
+		}
+		// Fragment outputs with a struct type are disallowed in singleDeclarationErrorCheck
+		return;
+	default:
+		break;
+	}
+
+	// Vertex shader outputs / fragment shader inputs have a different, slightly more lenient set of
+	// restrictions.
+	bool typeContainsIntegers = (type.type == EbtInt || type.type == EbtUInt ||
+	                            type.isStructureContainingType(EbtInt) ||
+	                            type.isStructureContainingType(EbtUInt));
+	if(typeContainsIntegers && qualifier != EvqFlatIn && qualifier != EvqFlatOut)
+	{
+		error(qualifierLocation, "must use 'flat' interpolation here", getQualifierString(qualifier));
+	}
+
+	if(type.type == EbtStruct)
+	{
+		// ESSL 3.00 sections 4.3.4 and 4.3.6.
+		// These restrictions are only implied by the ESSL 3.00 spec, but
+		// the ESSL 3.10 spec lists these restrictions explicitly.
+		if(type.array)
+		{
+			error(qualifierLocation, "cannot be an array of structures", getQualifierString(qualifier));
+		}
+		if(type.isStructureContainingArrays())
+		{
+			error(qualifierLocation, "cannot be a structure containing an array", getQualifierString(qualifier));
+		}
+		if(type.isStructureContainingType(EbtStruct))
+		{
+			error(qualifierLocation, "cannot be a structure containing a structure", getQualifierString(qualifier));
+		}
+		if(type.isStructureContainingType(EbtBool))
+		{
+			error(qualifierLocation, "cannot be a structure containing a bool", getQualifierString(qualifier));
+		}
+	}
+}
+
 TIntermAggregate *TParseContext::parseSingleDeclaration(TPublicType &publicType,
 	const TSourceLoc &identifierOrTypeLocation,
 	const TString &identifier)
@@ -1915,7 +2061,13 @@
 	// here.
 	//
 	TFunction *prevDec = static_cast<TFunction *>(symbolTable.find(function->getMangledName(), getShaderVersion()));
-	if(prevDec)
+	if(getShaderVersion() >= 300 && symbolTable.hasUnmangledBuiltIn(function->getName().c_str()))
+	{
+		// With ESSL 3.00, names of built-in functions cannot be redeclared as functions.
+		// Therefore overloading or redefining builtin functions is an error.
+		error(location, "Name of a built-in function cannot be redeclared as function", function->getName().c_str());
+	}
+	else if(prevDec)
 	{
 		if(prevDec->getReturnType() != function->getReturnType())
 		{
@@ -1969,84 +2121,7 @@
 	}
 	else
 	{
-		switch(publicType.type)
-		{
-		case EbtFloat:
-			if(publicType.isMatrix())
-			{
-				switch(publicType.getCols())
-				{
-				case 2:
-					switch(publicType.getRows())
-					{
-					case 2: op = EOpConstructMat2;  break;
-					case 3: op = EOpConstructMat2x3;  break;
-					case 4: op = EOpConstructMat2x4;  break;
-					}
-					break;
-				case 3:
-					switch(publicType.getRows())
-					{
-					case 2: op = EOpConstructMat3x2;  break;
-					case 3: op = EOpConstructMat3;  break;
-					case 4: op = EOpConstructMat3x4;  break;
-					}
-					break;
-				case 4:
-					switch(publicType.getRows())
-					{
-					case 2: op = EOpConstructMat4x2;  break;
-					case 3: op = EOpConstructMat4x3;  break;
-					case 4: op = EOpConstructMat4;  break;
-					}
-					break;
-				}
-			}
-			else
-			{
-				switch(publicType.getNominalSize())
-				{
-				case 1: op = EOpConstructFloat; break;
-				case 2: op = EOpConstructVec2;  break;
-				case 3: op = EOpConstructVec3;  break;
-				case 4: op = EOpConstructVec4;  break;
-				}
-			}
-			break;
-
-		case EbtInt:
-			switch(publicType.getNominalSize())
-			{
-			case 1: op = EOpConstructInt;   break;
-			case 2: op = EOpConstructIVec2; break;
-			case 3: op = EOpConstructIVec3; break;
-			case 4: op = EOpConstructIVec4; break;
-			}
-			break;
-
-		case EbtUInt:
-			switch(publicType.getNominalSize())
-			{
-			case 1: op = EOpConstructUInt;  break;
-			case 2: op = EOpConstructUVec2; break;
-			case 3: op = EOpConstructUVec3; break;
-			case 4: op = EOpConstructUVec4; break;
-			}
-			break;
-
-		case EbtBool:
-			switch(publicType.getNominalSize())
-			{
-			case 1: op = EOpConstructBool;  break;
-			case 2: op = EOpConstructBVec2; break;
-			case 3: op = EOpConstructBVec3; break;
-			case 4: op = EOpConstructBVec4; break;
-			}
-			break;
-
-		default: break;
-		}
-
+		op = TypeToConstructorOperator(TType(publicType));
 		if(op == EOpNull)
 		{
 			error(publicType.line, "cannot construct this type", getBasicString(publicType.type));
@@ -2717,9 +2792,8 @@
 				}
 				else
 				{
-					ConstantUnion *unionArray = new ConstantUnion[1];
-					unionArray->setIConst(i);
-					TIntermTyped *index = intermediate.addConstantUnion(unionArray, *fields[i]->type(), fieldLocation);
+					TIntermTyped *index = TIntermTyped::CreateIndexNode(i);
+					index->setLine(fieldLocation);
 					indexedExpression = intermediate.addIndex(EOpIndexDirectStruct, baseExpression, index, dotLocation);
 					indexedExpression->setType(*fields[i]->type());
 				}
@@ -3237,6 +3311,46 @@
 		{
 			return false;
 		}
+		break;
+	case EOpAdd:
+	case EOpSub:
+	case EOpDiv:
+	case EOpIMod:
+	case EOpBitShiftLeft:
+	case EOpBitShiftRight:
+	case EOpBitwiseAnd:
+	case EOpBitwiseXor:
+	case EOpBitwiseOr:
+	case EOpAddAssign:
+	case EOpSubAssign:
+	case EOpDivAssign:
+	case EOpIModAssign:
+	case EOpBitShiftLeftAssign:
+	case EOpBitShiftRightAssign:
+	case EOpBitwiseAndAssign:
+	case EOpBitwiseXorAssign:
+	case EOpBitwiseOrAssign:
+		if((left->isMatrix() && right->isVector()) || (left->isVector() && right->isMatrix()))
+		{
+			return false;
+		}
+
+		// Are the sizes compatible?
+		if(left->getNominalSize() != right->getNominalSize() || left->getSecondarySize() != right->getSecondarySize())
+		{
+			// If the nominal sizes of operands do not match:
+			// One of them must be a scalar.
+			if(!left->isScalar() && !right->isScalar())
+				return false;
+
+			// In the case of compound assignment other than multiply-assign,
+			// the right side needs to be a scalar. Otherwise a vector/matrix
+			// would be assigned to a scalar. A scalar can't be shifted by a
+			// vector either.
+			if(!right->isScalar() && (IsAssignment(op) || op == EOpBitShiftLeft || op == EOpBitShiftRight))
+				return false;
+		}
+		break;
 	default:
 		break;
 	}
diff --git a/src/OpenGL/compiler/ParseHelper.h b/src/OpenGL/compiler/ParseHelper.h
index 8733ef5..ea613eb 100644
--- a/src/OpenGL/compiler/ParseHelper.h
+++ b/src/OpenGL/compiler/ParseHelper.h
@@ -142,6 +142,7 @@
 	bool layoutLocationErrorCheck(const TSourceLoc& location, const TLayoutQualifier &layoutQualifier);
 	bool functionCallLValueErrorCheck(const TFunction *fnCandidate, TIntermAggregate *);
 	void es3InvariantErrorCheck(const TQualifier qualifier, const TSourceLoc &invariantLocation);
+	void checkInputOutputTypeIsValidES3(const TQualifier qualifier, const TPublicType &type, const TSourceLoc &qualifierLocation);
 
 	const TExtensionBehavior& extensionBehavior() const { return mDirectiveHandler.extensionBehavior(); }
 	bool supportsExtension(const char* extension);
diff --git a/src/OpenGL/compiler/SymbolTable.cpp b/src/OpenGL/compiler/SymbolTable.cpp
index 39023ae..004a1d7 100644
--- a/src/OpenGL/compiler/SymbolTable.cpp
+++ b/src/OpenGL/compiler/SymbolTable.cpp
@@ -121,6 +121,17 @@
 	return false;
 }
 
+bool TStructure::containsType(TBasicType type) const
+{
+	for(size_t i = 0; i < mFields->size(); ++i)
+	{
+		const TType *fieldType = (*mFields)[i]->type();
+		if(fieldType->getBasicType() == type || fieldType->isStructureContainingType(type))
+			return true;
+	}
+	return false;
+}
+
 bool TStructure::containsSamplers() const
 {
 	for(size_t i = 0; i < mFields->size(); ++i)
diff --git a/src/OpenGL/compiler/SymbolTable.h b/src/OpenGL/compiler/SymbolTable.h
index d8c6029..c4fdbfe 100644
--- a/src/OpenGL/compiler/SymbolTable.h
+++ b/src/OpenGL/compiler/SymbolTable.h
@@ -369,6 +369,7 @@
 	{
 		if(ptype1->getBasicType() == EbtGSampler2D)
 		{
+			insertUnmangledBuiltIn(name);
 			bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
 			insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler2D), ptype2, ptype3, ptype4, ptype5);
 			insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler2D), ptype2, ptype3, ptype4, ptype5);
@@ -376,6 +377,7 @@
 		}
 		else if(ptype1->getBasicType() == EbtGSampler3D)
 		{
+			insertUnmangledBuiltIn(name);
 			bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
 			insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler3D), ptype2, ptype3, ptype4, ptype5);
 			insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler3D), ptype2, ptype3, ptype4, ptype5);
@@ -383,6 +385,7 @@
 		}
 		else if(ptype1->getBasicType() == EbtGSamplerCube)
 		{
+			insertUnmangledBuiltIn(name);
 			bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
 			insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSamplerCube), ptype2, ptype3, ptype4, ptype5);
 			insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISamplerCube), ptype2, ptype3, ptype4, ptype5);
@@ -390,6 +393,7 @@
 		}
 		else if(ptype1->getBasicType() == EbtGSampler2DArray)
 		{
+			insertUnmangledBuiltIn(name);
 			bool gvec4 = (rvalue->getBasicType() == EbtGVec4);
 			insertBuiltIn(level, gvec4 ? new TType(EbtFloat, 4) : rvalue, name, new TType(EbtSampler2DArray), ptype2, ptype3, ptype4, ptype5);
 			insertBuiltIn(level, gvec4 ? new TType(EbtInt, 4) : rvalue, name, new TType(EbtISampler2DArray), ptype2, ptype3, ptype4, ptype5);
@@ -398,6 +402,7 @@
 		else if(IsGenType(rvalue) || IsGenType(ptype1) || IsGenType(ptype2) || IsGenType(ptype3))
 		{
 			ASSERT(!ptype4);
+			insertUnmangledBuiltIn(name);
 			insertBuiltIn(level, op, ext, GenType(rvalue, 1), name, GenType(ptype1, 1), GenType(ptype2, 1), GenType(ptype3, 1));
 			insertBuiltIn(level, op, ext, GenType(rvalue, 2), name, GenType(ptype1, 2), GenType(ptype2, 2), GenType(ptype3, 2));
 			insertBuiltIn(level, op, ext, GenType(rvalue, 3), name, GenType(ptype1, 3), GenType(ptype2, 3), GenType(ptype3, 3));
@@ -406,6 +411,7 @@
 		else if(IsVecType(rvalue) || IsVecType(ptype1) || IsVecType(ptype2) || IsVecType(ptype3))
 		{
 			ASSERT(!ptype4);
+			insertUnmangledBuiltIn(name);
 			insertBuiltIn(level, op, ext, VecType(rvalue, 2), name, VecType(ptype1, 2), VecType(ptype2, 2), VecType(ptype3, 2));
 			insertBuiltIn(level, op, ext, VecType(rvalue, 3), name, VecType(ptype1, 3), VecType(ptype2, 3), VecType(ptype3, 3));
 			insertBuiltIn(level, op, ext, VecType(rvalue, 4), name, VecType(ptype1, 4), VecType(ptype2, 4), VecType(ptype3, 4));
@@ -441,17 +447,20 @@
 				function->addParameter(param5);
 			}
 
+			ASSERT(hasUnmangledBuiltIn(name));
 			insert(level, *function);
 		}
 	}
 
 	void insertBuiltIn(ESymbolLevel level, TOperator op, TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0)
 	{
+		insertUnmangledBuiltIn(name);
 		insertBuiltIn(level, op, "", rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
 	}
 
 	void insertBuiltIn(ESymbolLevel level, TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0, TType *ptype5 = 0)
 	{
+		insertUnmangledBuiltIn(name);
 		insertBuiltIn(level, EOpNull, rvalue, name, ptype1, ptype2, ptype3, ptype4, ptype5);
 	}
 
@@ -518,6 +527,12 @@
 	void setGlobalInvariant() { mGlobalInvariant = true; }
 	bool getGlobalInvariant() const { return mGlobalInvariant; }
 
+	bool hasUnmangledBuiltIn(const char *name) { return mUnmangledBuiltinNames.count(std::string(name)) > 0; }
+
+private:
+	// Used to insert unmangled functions to check redeclaration of built-ins in ESSL 3.00.
+	void insertUnmangledBuiltIn(const char *name) { mUnmangledBuiltinNames.insert(std::string(name)); }
+
 protected:
 	ESymbolLevel currentLevel() const { return static_cast<ESymbolLevel>(table.size() - 1); }
 
@@ -525,6 +540,8 @@
 	typedef std::map< TBasicType, TPrecision > PrecisionStackLevel;
 	std::vector< PrecisionStackLevel > precisionStack;
 
+	std::set<std::string> mUnmangledBuiltinNames;
+
 	std::set<std::string> mInvariantVaryings;
 	bool mGlobalInvariant;
 };
diff --git a/src/OpenGL/compiler/Types.h b/src/OpenGL/compiler/Types.h
index f24f9e6..d4d98d0 100644
--- a/src/OpenGL/compiler/Types.h
+++ b/src/OpenGL/compiler/Types.h
@@ -132,6 +132,7 @@
 		return mDeepestNesting;
 	}
 	bool containsArrays() const;
+	bool containsType(TBasicType type) const;
 	bool containsSamplers() const;
 
 	bool equals(const TStructure &other) const;
@@ -381,6 +382,7 @@
 	int getSecondarySize() const { return secondarySize; }
 
 	bool isArray() const  { return array ? true : false; }
+	bool isUnsizedArray() const { return array && arraySize == 0; }
 	int getArraySize() const { return arraySize; }
 	void setArraySize(int s) { array = true; arraySize = s; }
 	int getMaxArraySize () const { return maxArraySize; }
@@ -468,6 +470,11 @@
 		return structure ? structure->containsArrays() : false;
 	}
 
+	bool isStructureContainingType(TBasicType t) const
+	{
+		return structure ? structure->containsType(t) : false;
+	}
+
 	bool isStructureContainingSamplers() const
 	{
 		return structure ? structure->containsSamplers() : false;
@@ -576,6 +583,16 @@
 		return userDef->isStructureContainingArrays();
 	}
 
+	bool isStructureContainingType(TBasicType t) const
+	{
+		if(!userDef)
+		{
+			return false;
+		}
+
+		return userDef->isStructureContainingType(t);
+	}
+
 	bool isMatrix() const
 	{
 		return primarySize > 1 && secondarySize > 1;
diff --git a/src/OpenGL/compiler/intermediate.h b/src/OpenGL/compiler/intermediate.h
index 740fb71..7757d89 100644
--- a/src/OpenGL/compiler/intermediate.h
+++ b/src/OpenGL/compiler/intermediate.h
@@ -238,6 +238,7 @@
 	EOpBitwiseOrAssign
 };
 
+extern TOperator TypeToConstructorOperator(const TType &type);
 extern const char* getOperatorString(TOperator op);
 
 class TIntermTraverser;
@@ -334,6 +335,7 @@
 	int registerSize() const { return type.registerSize(); }
 	int getArraySize() const { return type.getArraySize(); }
 
+	static TIntermTyped *CreateIndexNode(int index);
 protected:
 	TType type;
 };