Don't let shaders negate samplers

Prior to this change, the OpenGL compiler accepted all "non-struct"
"non-array" types for unary operations (++, --, and -). This ignored
the existence of sampler objects. If someone tried to negate a
sampler, then the compiler would tell the assembler to negate a non-
numerical type.

This change makes it so the GSL compiler only accepts unary operations
on numerical types (including vectors and matrices).

Also added a unittest that makes sure we gracefully fail to compile
bad unary operations.

Bug chromium:910883

Change-Id: Ia69056b31664900c3126cab42ecb8603d1a5d7db
Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/32448
Tested-by: Sean Risser <srisser@google.com>
Presubmit-Ready: Sean Risser <srisser@google.com>
Kokoro-Presubmit: kokoro <noreply+kokoro@google.com>
Reviewed-by: Alexis Hétu <sugoi@google.com>
diff --git a/src/OpenGL/compiler/Intermediate.cpp b/src/OpenGL/compiler/Intermediate.cpp
index 9f68dc7..2c47256 100644
--- a/src/OpenGL/compiler/Intermediate.cpp
+++ b/src/OpenGL/compiler/Intermediate.cpp
@@ -497,7 +497,7 @@
 	case EOpPostDecrement:
 	case EOpPreDecrement:
 	case EOpNegative:
-		if (child->getType().getBasicType() == EbtStruct || child->getType().isArray())
+		if (!child->getType().isScalar() && !child->getType().isVector() && !child->getType().isMatrix())
 			return 0;
 	default: break;
 	}
diff --git a/src/OpenGL/compiler/Types.h b/src/OpenGL/compiler/Types.h
index e031f9b..846b240 100644
--- a/src/OpenGL/compiler/Types.h
+++ b/src/OpenGL/compiler/Types.h
@@ -444,7 +444,7 @@
 	TInterfaceBlock *getAsInterfaceBlock() const { return isInterfaceBlock() ? getInterfaceBlock() : nullptr; }
 
 	bool isVector() const { return primarySize > 1 && !isMatrix(); }
-	bool isScalar() const { return primarySize == 1 && !isMatrix() && !structure && !isInterfaceBlock(); }
+	bool isScalar() const { return primarySize == 1 && !isMatrix() && !structure && !isInterfaceBlock() && !IsSampler(getBasicType()); }
 	bool isRegister() const { return !isMatrix() && !structure && !array && !isInterfaceBlock(); }   // Fits in a 4-element register
 	bool isStruct() const { return structure != 0; }
 	bool isScalarInt() const { return isScalar() && IsInteger(type); }
diff --git a/tests/GLESUnitTests/unittests.cpp b/tests/GLESUnitTests/unittests.cpp
index f01b93b..45d92ce 100644
--- a/tests/GLESUnitTests/unittests.cpp
+++ b/tests/GLESUnitTests/unittests.cpp
@@ -381,23 +381,26 @@
 		checkCompiles("", s);
 	}
 
-	void checkCompileFails(GLuint glShader, std::string source)
+	void checkCompileFails(GLenum glShaderType, std::string source)
 	{
-		GLchar buf[1024];
+		Initialize(3, false);
+
 		GLint compileStatus = 0;
 		const char *c_source[1] = { source.c_str() };
+		GLuint glShader = glCreateShader(glShaderType);
 
 		glShaderSource(glShader, 1, c_source, nullptr);
 		glCompileShader(glShader);
 
-		EXPECT_GLENUM_EQ(GL_NONE, glGetError());
+		EXPECT_GLENUM_EQ(GL_NO_ERROR, glGetError());
 
 		glGetShaderiv(glShader, GL_COMPILE_STATUS, &compileStatus);
-		glGetShaderInfoLog(glShader, sizeof(buf), nullptr, buf);
 
-		EXPECT_EQ(compileStatus, GL_FALSE) << "Compile status: " << std::endl << buf;
+		EXPECT_EQ(compileStatus, GL_FALSE);
 
 		glDeleteShader(glShader);
+
+		Uninitialize();
 	}
 
 	void checkCompileFails(std::string s)
@@ -429,8 +432,8 @@
 		vs = replace(vs, "$INSERT", s);
 		fs = replace(fs, "$INSERT", s);
 
-		checkCompileFails(glCreateShader(GL_VERTEX_SHADER), vs);
-		checkCompileFails(glCreateShader(GL_FRAGMENT_SHADER), fs);
+		checkCompileFails(GL_VERTEX_SHADER, vs);
+		checkCompileFails(GL_FRAGMENT_SHADER, fs);
 	}
 
 	EGLDisplay getDisplay() const { return display; }
@@ -1823,8 +1826,6 @@
 // GL_MAX_{VERTEX/FRAGMENT}_UNIFORM_VECTOR.
 TEST_F(SwiftShaderTest, CompilerLimits_ArraySize)
 {
-	Initialize(3, false);
-
 	checkCompileFails(
 		"uniform float u_var[100000000];\n"
 		"float F(float f) { return u_var[2]; }\n");
@@ -1832,8 +1833,35 @@
 		"struct structType { mediump sampler2D m0; mediump samplerCube m1; }; \n"
 		"uniform structType u_var[100000000];\n"
 		"float F(float f) { return texture(u_var[2].m1, vec3(0.0)), vec4(0.26, 1.72, 0.60, 0.12).x; }\n");
+}
 
-	Uninitialize();
+// Test that the compiler rejects negations of things that can't be negated.
+TEST_F(SwiftShaderTest, BadNegation)
+{
+	checkCompileFails(
+		"uniform samplerCube m;\n"
+		"float F (float f) { vec4 ret = texture(-m, vec3(f)); return ret.x; }\n"
+	);
+	checkCompileFails(
+		"uniform sampler2D m[9];\n"
+		"vec4 G (sampler2D X[9]) { return texture(X[0], vec2(0.0f)); }"
+		"float F (float f) { vec4 ret = G(-m); return ret.x; }\n"
+	);
+	checkCompileFails(
+		"struct structType { int a; float b; };\n"
+		"uniform structType m;\n"
+		"float F (float f) { structType n = -m; return f; }\n"
+	);
+	checkCompileFails(
+		"struct structType { int a; float b; };\n"
+		"uniform structType m[4];\n"
+		"float F (float f) { structType n[4] = -m; return f; }\n"
+	);
+	checkCompileFails(
+		"uniform float m[4];\n"
+		"float G (float f[4]) { return f[0]; }\n"
+		"float F (float f) { return G(-m); }\n"
+	);
 }
 
 #ifndef EGL_ANGLE_iosurface_client_buffer