From 2eb135506a492888355483c7d169eaaf8e57c8cb Mon Sep 17 00:00:00 2001
From: John Kessenich <cepheus@frii.com>
Date: Wed, 7 Jun 2017 17:15:38 -0600
Subject: [PATCH] GLSL: Fix #396: Error when 'defined' comes from macro
 expansion.

---
 Test/baseResults/cppSimple.vert.out                 |  4 +++-
 Test/cppSimple.vert                                 | 10 ++++++++++
 glslang/MachineIndependent/preprocessor/Pp.cpp      |  8 ++++++++
 glslang/MachineIndependent/preprocessor/PpContext.h |  3 +++
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/Test/baseResults/cppSimple.vert.out b/Test/baseResults/cppSimple.vert.out
index 5b8794149..1b6e6b50d 100644
--- a/Test/baseResults/cppSimple.vert.out
+++ b/Test/baseResults/cppSimple.vert.out
@@ -90,8 +90,10 @@ ERROR: 12:9504: '#if' : unexpected tokens following directive
 ERROR: 12:9506: '#error' : \ 377  
 ERROR: 12:9507: '#error' : \ 376  
 ERROR: 12:9508: '#error' : \ 377  
+ERROR: 12:9602: 'defined' : cannot use in preprocessor expression when expanded from macros 
+ERROR: 12:9603: '#error' : DEF_DEFINED then  
 ERROR: 12:10002: '' : missing #endif 
-ERROR: 88 compilation errors.  No code generated.
+ERROR: 90 compilation errors.  No code generated.
 
 
 Shader version: 400
diff --git a/Test/cppSimple.vert b/Test/cppSimple.vert
index 198203a69..fdd14221b 100644
--- a/Test/cppSimple.vert
+++ b/Test/cppSimple.vert
@@ -337,6 +337,16 @@ int aoeua = FOOOM;
 #error \ 376
 #error \377
 
+// ERROR for macro expansion to yield 'defined'
+#line 9600
+#define DEF_MAC
+#define DEF_DEFINED defined
+#if DEF_DEFINED DEF_MAC
+#error DEF_DEFINED then
+#else
+#error DEF_DEFINED else
+#endif
+
 #line 10000
 #if 1
 #else
diff --git a/glslang/MachineIndependent/preprocessor/Pp.cpp b/glslang/MachineIndependent/preprocessor/Pp.cpp
index da432bd54..5c6e24797 100644
--- a/glslang/MachineIndependent/preprocessor/Pp.cpp
+++ b/glslang/MachineIndependent/preprocessor/Pp.cpp
@@ -393,6 +393,14 @@ int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, boo
     TSourceLoc loc = ppToken->loc;  // because we sometimes read the newline before reporting the error
     if (token == PpAtomIdentifier) {
         if (strcmp("defined", ppToken->name) == 0) {
+            if (isMacroInput()) {
+                if (parseContext.relaxedErrors())
+                    parseContext.ppWarn(ppToken->loc, "nonportable when expanded from macros for preprocessor expression",
+                                                      "defined", "");
+                else
+                    parseContext.ppError(ppToken->loc, "cannot use in preprocessor expression when expanded from macros",
+                                                       "defined", "");
+            }
             bool needclose = 0;
             token = scanToken(ppToken);
             if (token == '(') {
diff --git a/glslang/MachineIndependent/preprocessor/PpContext.h b/glslang/MachineIndependent/preprocessor/PpContext.h
index a459d9a2a..de48e2794 100644
--- a/glslang/MachineIndependent/preprocessor/PpContext.h
+++ b/glslang/MachineIndependent/preprocessor/PpContext.h
@@ -200,6 +200,7 @@ public:
         virtual void ungetch() = 0;
         virtual bool peekPasting() { return false; }          // true when about to see ##
         virtual bool endOfReplacementList() { return false; } // true when at the end of a macro replacement list (RHS of #define)
+        virtual bool isMacroInput() { return false; }
 
         // Will be called when we start reading tokens from this instance
         virtual void notifyActivated() {}
@@ -306,6 +307,7 @@ protected:
     void ungetChar() { inputStack.back()->ungetch(); }
     bool peekPasting() { return !inputStack.empty() && inputStack.back()->peekPasting(); }
     bool endOfReplacementList() { return inputStack.empty() || inputStack.back()->endOfReplacementList(); }
+    bool isMacroInput() { return inputStack.size() > 0 && inputStack.back()->isMacroInput(); }
 
     static const int maxIfNesting = 64;
 
@@ -329,6 +331,7 @@ protected:
         virtual void ungetch() override { assert(0); }
         bool peekPasting() override { return prepaste; }
         bool endOfReplacementList() override { return mac->body.atEnd(); }
+        bool isMacroInput() override { return true; }
 
         MacroSymbol *mac;
         TVector<TokenStream*> args;
-- 
GitLab