Error when encountering non-preprocessor tokens before #extension in ESSL3.

BUG=angleproject:1047

Change-Id: I4a548270f651e35b2c8d1ab5d0f46185230c5f74
Reviewed-on: https://chromium-review.googlesource.com/281216
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Tested-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/compiler/preprocessor/DiagnosticsBase.cpp b/src/compiler/preprocessor/DiagnosticsBase.cpp
index 5a1c390..c74c42c 100644
--- a/src/compiler/preprocessor/DiagnosticsBase.cpp
+++ b/src/compiler/preprocessor/DiagnosticsBase.cpp
@@ -117,6 +117,8 @@
         return "invalid pragma";
       case PP_INVALID_PRAGMA_VALUE:
         return "invalid pragma value, must be 'on' or 'off'";
+      case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3:
+        return "extension directive must occur before any non-preprocessor tokens in ESSL3";
       // Errors end.
       // Warnings begin.
       case PP_EOF_IN_DIRECTIVE:
@@ -125,8 +127,8 @@
         return "unexpected token after conditional expression";
       case PP_UNRECOGNIZED_PRAGMA:
         return "unrecognized pragma";
-      case PP_NON_PP_TOKEN_BEFORE_EXTENSION:
-        return "extension directive must occur before any non-preprocessor tokens";
+      case PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1:
+        return "extension directive should occur before any non-preprocessor tokens";
       // Warnings end.
       default:
         assert(false);
diff --git a/src/compiler/preprocessor/DiagnosticsBase.h b/src/compiler/preprocessor/DiagnosticsBase.h
index 7aaadb4..40142c5 100644
--- a/src/compiler/preprocessor/DiagnosticsBase.h
+++ b/src/compiler/preprocessor/DiagnosticsBase.h
@@ -66,12 +66,13 @@
         PP_INVALID_LINE_DIRECTIVE,
         PP_INVALID_PRAGMA,
         PP_INVALID_PRAGMA_VALUE,
+        PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
         PP_ERROR_END,
 
         PP_WARNING_BEGIN,
         PP_EOF_IN_DIRECTIVE,
         PP_UNRECOGNIZED_PRAGMA,
-        PP_NON_PP_TOKEN_BEFORE_EXTENSION,
+        PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
         PP_WARNING_END
     };
 
diff --git a/src/compiler/preprocessor/DirectiveParser.cpp b/src/compiler/preprocessor/DirectiveParser.cpp
index e94f1db..fecfdae 100644
--- a/src/compiler/preprocessor/DirectiveParser.cpp
+++ b/src/compiler/preprocessor/DirectiveParser.cpp
@@ -215,7 +215,8 @@
       mTokenizer(tokenizer),
       mMacroSet(macroSet),
       mDiagnostics(diagnostics),
-      mDirectiveHandler(directiveHandler)
+      mDirectiveHandler(directiveHandler),
+      mShaderVersion(100)
 {
 }
 
@@ -722,8 +723,17 @@
     }
     if (valid && mSeenNonPreprocessorToken)
     {
-        mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION,
-                             token->location, token->text);
+        if (mShaderVersion >= 300)
+        {
+            mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3,
+                                 token->location, token->text);
+            valid = false;
+        }
+        else
+        {
+            mDiagnostics->report(Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1,
+                                 token->location, token->text);
+        }
     }
     if (valid)
         mDirectiveHandler->handleExtension(token->location, name, behavior);
@@ -811,6 +821,7 @@
     if (valid)
     {
         mDirectiveHandler->handleVersion(token->location, version);
+        mShaderVersion = version;
     }
 }
 
diff --git a/src/compiler/preprocessor/DirectiveParser.h b/src/compiler/preprocessor/DirectiveParser.h
index c297bcd..1df67ec 100644
--- a/src/compiler/preprocessor/DirectiveParser.h
+++ b/src/compiler/preprocessor/DirectiveParser.h
@@ -77,6 +77,7 @@
     MacroSet *mMacroSet;
     Diagnostics *mDiagnostics;
     DirectiveHandler *mDirectiveHandler;
+    int mShaderVersion;
 };
 
 }  // namespace pp
diff --git a/src/tests/preprocessor_tests/extension_test.cpp b/src/tests/preprocessor_tests/extension_test.cpp
index 0b8cf88..6a819d1 100644
--- a/src/tests/preprocessor_tests/extension_test.cpp
+++ b/src/tests/preprocessor_tests/extension_test.cpp
@@ -66,6 +66,39 @@
     preprocess(str, expected);
 }
 
+TEST_F(ExtensionTest, ExtensionAfterNonPreProcessorTokenESSL1)
+{
+    const char *str = "int baz = 1;\n"
+                      "#extension foo : bar\n";
+    const char *expected = "int baz = 1;\n\n";
+
+    using testing::_;
+    // Directive successfully parsed.
+    EXPECT_CALL(mDirectiveHandler,
+        handleExtension(pp::SourceLocation(0, 2), "foo", "bar"));
+    // Expect a warning about extension pragmas after non-preprocessor tokens.
+    EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL1, _, _));
+
+    preprocess(str, expected);
+}
+
+TEST_F(ExtensionTest, ExtensionAfterNonPreProcessorTokenESSL3)
+{
+    const char *str = "#version 300 es\n"
+                      "int baz = 1;\n"
+                      "#extension foo : bar\n";
+    const char *expected = "\nint baz = 1;\n\n";
+
+    using testing::_;
+    // Directive successfully parsed.
+    EXPECT_CALL(mDirectiveHandler,
+        handleVersion(pp::SourceLocation(0, 1), 300));
+    // Expect a error about extension pragmas after non-preprocessor tokens.
+    EXPECT_CALL(mDiagnostics, print(pp::Diagnostics::PP_NON_PP_TOKEN_BEFORE_EXTENSION_ESSL3, _, _));
+
+    preprocess(str, expected);
+}
+
 struct ExtensionTestParam
 {
     const char* str;