From 9c1280b225e5e9f0d1a35bce96e67c92bbb7330c Mon Sep 17 00:00:00 2001
From: Lei Zhang <antiagainst@google.com>
Date: Thu, 16 Jul 2015 17:33:10 -0400
Subject: [PATCH] Use extension framework to enable #include directive.

This patch introduces a new extension, GL_GOOGLE_include_directive,
to enable support #include directives. It depends on the extension
GL_GOOGLE_cpp_style_line_directive.
---
 .../preprocessor.include.disabled.vert.err    | 13 +++++++++++++
 ...=> preprocessor.include.disabled.vert.out} |  0
 ... => preprocessor.include.enabled.vert.err} |  0
 .../preprocessor.include.enabled.vert.out     |  0
 ...ert => preprocessor.include.disabled.vert} | 13 +++++++------
 Test/preprocessor.include.enabled.vert        |  7 +++++++
 Test/test-preprocessor-list                   |  3 ++-
 glslang/MachineIndependent/ParseHelper.h      |  2 +-
 glslang/MachineIndependent/Versions.cpp       | 19 ++++++++++++++++---
 glslang/MachineIndependent/Versions.h         |  2 ++
 .../MachineIndependent/preprocessor/Pp.cpp    |  5 +++--
 11 files changed, 51 insertions(+), 13 deletions(-)
 create mode 100644 Test/baseResults/preprocessor.include.disabled.vert.err
 rename Test/baseResults/{preprocessor.include.vert.out => preprocessor.include.disabled.vert.out} (100%)
 rename Test/baseResults/{preprocessor.include.vert.err => preprocessor.include.enabled.vert.err} (100%)
 create mode 100644 Test/baseResults/preprocessor.include.enabled.vert.out
 rename Test/{preprocessor.include.vert => preprocessor.include.disabled.vert} (76%)
 create mode 100644 Test/preprocessor.include.enabled.vert

diff --git a/Test/baseResults/preprocessor.include.disabled.vert.err b/Test/baseResults/preprocessor.include.disabled.vert.err
new file mode 100644
index 000000000..85428de85
--- /dev/null
+++ b/Test/baseResults/preprocessor.include.disabled.vert.err
@@ -0,0 +1,13 @@
+ERROR: 0:8000: '#include' : required extension not requested: GL_GOOGLE_include_directive
+ERROR: 0:8000: '#include' : must be followed by a file designation
+ERROR: 0:8001: '#include' : required extension not requested: GL_GOOGLE_include_directive
+ERROR: 0:8001: '#include' : must be followed by a file designation
+ERROR: 0:8002: '#include' : required extension not requested: GL_GOOGLE_include_directive
+ERROR: 0:8002: '#error' : unexpected include directive
+ERROR: 0:8003: '#include' : required extension not requested: GL_GOOGLE_include_directive
+ERROR: 0:8003: '#include' : extra content after file designation
+ERROR: 0:8004: '#include' : required extension not requested: GL_GOOGLE_include_directive
+ERROR: 0:8004: '#error' : unexpected include directive
+ERROR: 10 compilation errors.  No code generated.
+
+
diff --git a/Test/baseResults/preprocessor.include.vert.out b/Test/baseResults/preprocessor.include.disabled.vert.out
similarity index 100%
rename from Test/baseResults/preprocessor.include.vert.out
rename to Test/baseResults/preprocessor.include.disabled.vert.out
diff --git a/Test/baseResults/preprocessor.include.vert.err b/Test/baseResults/preprocessor.include.enabled.vert.err
similarity index 100%
rename from Test/baseResults/preprocessor.include.vert.err
rename to Test/baseResults/preprocessor.include.enabled.vert.err
diff --git a/Test/baseResults/preprocessor.include.enabled.vert.out b/Test/baseResults/preprocessor.include.enabled.vert.out
new file mode 100644
index 000000000..e69de29bb
diff --git a/Test/preprocessor.include.vert b/Test/preprocessor.include.disabled.vert
similarity index 76%
rename from Test/preprocessor.include.vert
rename to Test/preprocessor.include.disabled.vert
index 512327baa..130d928e5 100644
--- a/Test/preprocessor.include.vert
+++ b/Test/preprocessor.include.disabled.vert
@@ -1,6 +1,7 @@
-#line 8000
-#include
-#include 123
-#include "foo"
-#include "foo" garbage
-#include "no-eol"
\ No newline at end of file
+#line 8000
+#include
+#include 123
+#include "foo"
+#include "foo" garbage
+#include "no-eol"
+
diff --git a/Test/preprocessor.include.enabled.vert b/Test/preprocessor.include.enabled.vert
new file mode 100644
index 000000000..ecdf466e1
--- /dev/null
+++ b/Test/preprocessor.include.enabled.vert
@@ -0,0 +1,7 @@
+#extension GL_GOOGLE_include_directive : enable
+#line 8000
+#include
+#include 123
+#include "foo"
+#include "foo" garbage
+#include "no-eol"
diff --git a/Test/test-preprocessor-list b/Test/test-preprocessor-list
index 195b4a79c..cd2381a54 100644
--- a/Test/test-preprocessor-list
+++ b/Test/test-preprocessor-list
@@ -4,7 +4,8 @@ preprocessor.edge_cases.vert
 preprocessor.errors.vert
 preprocessor.extensions.vert
 preprocessor.function_macro.vert
-preprocessor.include.vert
+preprocessor.include.enabled.vert
+preprocessor.include.disabled.vert
 preprocessor.line.vert
 preprocessor.line.frag
 preprocessor.pragma.vert
diff --git a/glslang/MachineIndependent/ParseHelper.h b/glslang/MachineIndependent/ParseHelper.h
index f0c63bb3d..e537ec629 100644
--- a/glslang/MachineIndependent/ParseHelper.h
+++ b/glslang/MachineIndependent/ParseHelper.h
@@ -235,7 +235,7 @@ public:
     void requireStage(const TSourceLoc&, EShLanguage, const char* featureDesc);
     void checkDeprecated(const TSourceLoc&, int queryProfiles, int depVersion, const char* featureDesc);
     void requireNotRemoved(const TSourceLoc&, int queryProfiles, int removedVersion, const char* featureDesc);
-    void requireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc);
+    void requireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc, bool requiredByPreprocessor = false);
     TExtensionBehavior getExtensionBehavior(const char*);
     bool extensionTurnedOn(const char* const extension);
     bool extensionsTurnedOn(int numExtensions, const char* const extensions[]);
diff --git a/glslang/MachineIndependent/Versions.cpp b/glslang/MachineIndependent/Versions.cpp
index 28ad10cb6..46275b6c8 100644
--- a/glslang/MachineIndependent/Versions.cpp
+++ b/glslang/MachineIndependent/Versions.cpp
@@ -174,7 +174,9 @@ void TParseContext::initializeExtensionBehavior()
     extensionBehavior[E_GL_ARB_viewport_array]               = EBhDisable;
 //    extensionBehavior[E_GL_ARB_cull_distance]                = EBhDisable;    // present for 4.5, but need extension control over block members
 
+    // #line and #include
     extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive]          = EBhDisable;
+    extensionBehavior[E_GL_GOOGLE_include_directive]                 = EBhDisable;
 
     // AEP
     extensionBehavior[E_GL_ANDROID_extension_pack_es31a]             = EBhDisablePartial;
@@ -219,7 +221,9 @@ const char* TParseContext::getPreamble()
             "#define GL_OES_EGL_image_external 1\n"
             "#define GL_EXT_shader_texture_lod 1\n"
 
+            // #line and #include
             "#define GL_GOOGLE_cpp_style_line_directive 1\n"
+            "#define GL_GOOGLE_include_directive 1\n"
 
             // AEP
             "#define GL_ANDROID_extension_pack_es31a 1\n"
@@ -270,6 +274,7 @@ const char* TParseContext::getPreamble()
             "#define GL_ARB_viewport_array 1\n"
 
             "#define GL_GOOGLE_cpp_style_line_directive 1\n"
+            "#define GL_GOOGLE_include_directive 1\n"
 //            "#define GL_ARB_cull_distance 1\n"    // present for 4.5, but need extension control over block members
             ;
     }
@@ -410,7 +415,7 @@ void TParseContext::requireNotRemoved(const TSourceLoc& loc, int profileMask, in
 // Use when there are no profile/version to check, it's just an error if one of the
 // extensions is not present.
 //
-void TParseContext::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc)
+void TParseContext::requireExtensions(const TSourceLoc& loc, int numExtensions, const char* const extensions[], const char* featureDesc, bool requiredByPreprocessor)
 {
     // First, see if any of the extensions are enabled
     for (int i = 0; i < numExtensions; ++i) {
@@ -437,9 +442,15 @@ void TParseContext::requireExtensions(const TSourceLoc& loc, int numExtensions,
 
     // If we get this far, give errors explaining what extensions are needed
     if (numExtensions == 1)
-        error(loc, "required extension not requested:", featureDesc, extensions[0]);
+        if (requiredByPreprocessor)
+            ppError(loc, "required extension not requested:", featureDesc, extensions[0]);
+        else
+            error(loc, "required extension not requested:", featureDesc, extensions[0]);
     else {
-        error(loc, "required extension not requested:", featureDesc, "Possible extensions include:");
+        if (requiredByPreprocessor)
+            ppError(loc, "required extension not requested:", featureDesc, "Possible extensions include:");
+        else
+            error(loc, "required extension not requested:", featureDesc, "Possible extensions include:");
         for (int i = 0; i < numExtensions; ++i)
             infoSink.info.message(EPrefixNone, extensions[i]);
     }
@@ -525,6 +536,8 @@ void TParseContext::updateExtensionBehavior(int line, const char* extension, con
         updateExtensionBehavior(line, "GL_EXT_shader_io_blocks", behaviorString);
     else if (strcmp(extension, "GL_OES_tessellation_shader") == 0)
         updateExtensionBehavior(line, "GL_OES_shader_io_blocks", behaviorString);
+    else if (strcmp(extension, "GL_GOOGLE_include_directive") == 0)
+        updateExtensionBehavior(line, "GL_GOOGLE_cpp_style_line_directive", behaviorString);
 }
 
 void TParseContext::updateExtensionBehavior(const char* extension, TExtensionBehavior behavior)
diff --git a/glslang/MachineIndependent/Versions.h b/glslang/MachineIndependent/Versions.h
index ae8fd414a..bb3cbc4de 100644
--- a/glslang/MachineIndependent/Versions.h
+++ b/glslang/MachineIndependent/Versions.h
@@ -112,7 +112,9 @@ const char* const E_GL_ARB_shader_texture_image_samples = "GL_ARB_shader_texture
 const char* const E_GL_ARB_viewport_array               = "GL_ARB_viewport_array";
 //const char* const E_GL_ARB_cull_distance            = "GL_ARB_cull_distance";  // present for 4.5, but need extension control over block members
 
+// #line and #include
 const char* const E_GL_GOOGLE_cpp_style_line_directive          = "GL_GOOGLE_cpp_style_line_directive";
+const char* const E_GL_GOOGLE_include_directive                 = "GL_GOOGLE_include_directive";
 
 // AEP
 const char* const E_GL_ANDROID_extension_pack_es31a             = "GL_ANDROID_extension_pack_es31a";
diff --git a/glslang/MachineIndependent/preprocessor/Pp.cpp b/glslang/MachineIndependent/preprocessor/Pp.cpp
index 9e1268241..c17004b63 100644
--- a/glslang/MachineIndependent/preprocessor/Pp.cpp
+++ b/glslang/MachineIndependent/preprocessor/Pp.cpp
@@ -661,7 +661,7 @@ int TPpContext::CPPline(TPpToken* ppToken)
 
         if (token != '\n') {
             if (token == PpAtomConstString) {
-                parseContext.requireExtensions(directiveLoc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based #line");
+                parseContext.requireExtensions(directiveLoc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based #line", true);
                 // We need to save a copy of the string instead of pointing
                 // to the name field of the token since the name field
                 // will likely be overwritten by the next token scan.
@@ -878,6 +878,7 @@ int TPpContext::readCPPline(TPpToken* ppToken)
             token = CPPifdef(0, ppToken);
             break;
         case PpAtomInclude:
+            parseContext.requireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include", true);
             token = CPPinclude(ppToken);
             break;
         case PpAtomLine:
@@ -1002,7 +1003,7 @@ int TPpContext::MacroExpand(int atom, TPpToken* ppToken, bool expandUndef, bool
 
     case PpAtomFileMacro: {
         if (const char* current_file = parseContext.getCurrentLoc().name) {
-            parseContext.requireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__");
+            parseContext.requireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based __FILE__", true);
             sprintf(ppToken->name, "\"%s\"", current_file);
         } else {
             ppToken->ival = parseContext.getCurrentLoc().string;
-- 
GitLab