From 7fc366919526b3a2e05dcd7814c2d1ec366a7b95 Mon Sep 17 00:00:00 2001 From: John Kessenich Date: Fri, 6 Dec 2013 18:19:22 +0000 Subject: [PATCH] Preprocessor: Add short-circuit logic so ES errors are not given on undefined variables that are short circuited in && and || preprocessing expressions. git-svn-id: https://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang@24390 e7fa87d3-cd2b-0410-9028-fcbf551c1848 --- Test/baseResults/cppComplexExpr.vert.out | 21 ++++-- Test/cppComplexExpr.vert | 60 ++++++++++++++++ glslang/Include/revision.h | 4 +- .../MachineIndependent/preprocessor/Pp.cpp | 68 +++++++++++-------- .../preprocessor/PpContext.h | 2 +- 5 files changed, 117 insertions(+), 38 deletions(-) diff --git a/Test/baseResults/cppComplexExpr.vert.out b/Test/baseResults/cppComplexExpr.vert.out index 6b8b01a8..11e7c4e9 100644 --- a/Test/baseResults/cppComplexExpr.vert.out +++ b/Test/baseResults/cppComplexExpr.vert.out @@ -11,11 +11,22 @@ ERROR: 0:94: 'macro expansion' : unexpected '#' foobar ERROR: 0:95: 'preprocessor evaluation' : bad expression ERROR: 0:100: 'preprocessor evaluation' : bad expression ERROR: 0:100: '#if' : unexpected tokens following directive -ERROR: 0:103: 'macro expansion' : unexpected '#' foobar -ERROR: 0:103: 'preprocessor evaluation' : undefined macro in expression -ERROR: 0:103: '#if' : unexpected tokens following directive -ERROR: 0:104: '' : missing #endif -ERROR: 16 compilation errors. No code generated. +ERROR: 0:102: 'macro expansion' : unexpected '#' foobar +ERROR: 0:102: 'preprocessor evaluation' : undefined macro in expression not allowed in es profile endif +ERROR: 0:108: 'preprocessor evaluation' : undefined macro in expression not allowed in es profile UNDEF +ERROR: 0:111: '#error' : good 0 +ERROR: 0:115: '#error' : good 1 +ERROR: 0:120: 'preprocessor evaluation' : undefined macro in expression not allowed in es profile UNDEF +ERROR: 0:123: 'preprocessor evaluation' : undefined macro in expression not allowed in es profile UNDEF +ERROR: 0:129: '#error' : good 1 +ERROR: 0:133: '#error' : good 3 +ERROR: 0:139: '#error' : good 4 +ERROR: 0:144: 'preprocessor evaluation' : undefined macro in expression not allowed in es profile UNDEF +ERROR: 0:153: 'preprocessor evaluation' : undefined macro in expression not allowed in es profile UNDEF +ERROR: 0:156: 'preprocessor evaluation' : undefined macro in expression not allowed in es profile UNDEF2 +ERROR: 0:159: 'preprocessor evaluation' : undefined macro in expression not allowed in es profile UNDEF2 +ERROR: 0:10002: '' : missing #endif +ERROR: 27 compilation errors. No code generated. ERROR: node is still EOpNull! diff --git a/Test/cppComplexExpr.vert b/Test/cppComplexExpr.vert index 3fb206b9..c2c1360a 100644 --- a/Test/cppComplexExpr.vert +++ b/Test/cppComplexExpr.vert @@ -99,6 +99,66 @@ float c = foobar(1.1, 2.2 #if foobar(1.1, 2.2 ) #if foobar(1.1, 2.2 +#endif +#endif +#define VAL0 0 +#define VAL1 1 + +#if UNDEF +#error bad 0 +#else +#error good 0 +#endif + +#if VAL1 || UNDEF +#error good 1 +#else +#error bad 1 +#endif + +#if VAL1 && UNDEF // UNDEF ERROR +#endif + +#if VAL0 || UNDEF // UNDEF ERROR +#endif + +#if VAL0 && UNDEF +#error bad 2 +#else +#error good 1 +#endif + +#if VAL1 || (VAL1 && UNDEF) +#error good 3 +#else +#error bad 3 +#endif + +#if VAL1 && (VAL1 || UNDEF) +#error good 4 +#else +#error bad 4 +#endif + +#if VAL1 < VAL1 || VAL1 > VAL1 || UNDEF // UNDEF ERROR +#endif + +#if VAL1 < VAL1 || VAL1 > VAL1 && UNDEF +#endif + +#if VAL1 || UNDEF && UNDEF2 +#endif + +#if VAL0 || UNDEF && UNDEF2 // UNDEF ERROR +#endif + +#if (VAL1 || UNDEF) && UNDEF2 // UNDEF2 ERROR +#endif + +#if (VAL0 && UNDEF) || UNDEF2 // UNDEF2 ERROR +#endif + +#line 10000 #if 0 // ERROR, EOF \ No newline at end of file diff --git a/glslang/Include/revision.h b/glslang/Include/revision.h index 1e71420e..86332b96 100644 --- a/glslang/Include/revision.h +++ b/glslang/Include/revision.h @@ -9,5 +9,5 @@ // source have to figure out how to create revision.h just to get a build // going. However, if it is not updated, it can be a version behind. -#define GLSLANG_REVISION "24378" -#define GLSLANG_DATE "2013/12/05 14:51:40" +#define GLSLANG_REVISION "24387" +#define GLSLANG_DATE "2013/12/06 09:13:47" diff --git a/glslang/MachineIndependent/preprocessor/Pp.cpp b/glslang/MachineIndependent/preprocessor/Pp.cpp index 67fca136..5e43c2a1 100644 --- a/glslang/MachineIndependent/preprocessor/Pp.cpp +++ b/glslang/MachineIndependent/preprocessor/Pp.cpp @@ -408,7 +408,7 @@ namespace { }; -struct Tbinops { +struct { int token, precedence, (*op)(int, int); } binop[] = { { CPP_OR_OP, LOGOR, op_logor }, @@ -431,7 +431,7 @@ struct Tbinops { { '%', MUL, op_mod }, }; -struct tunops { +struct { int token, (*op)(int); } unop[] = { { '+', op_pos }, @@ -440,13 +440,10 @@ struct tunops { { '!', op_not }, }; -#define ALEN(A) (sizeof(A)/sizeof(A[0])) +#define NUM_ELEMENTS(A) (sizeof(A) / sizeof(A[0])) -int TPpContext::eval(int token, int precedence, int& res, bool& err, TPpToken* ppToken) +int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken) { - int i, val; - Symbol *s; - if (token == CPP_IDENTIFIER) { if (ppToken->atom == definedAtom) { bool needclose = 0; @@ -462,6 +459,7 @@ int TPpContext::eval(int token, int precedence, int& res, bool& err, TPpToken* p return token; } + Symbol* s; res = (s = LookUpSymbol(ppToken->atom)) ? !s->mac.undef : 0; token = currentInput->scan(this, currentInput, ppToken); if (needclose) { @@ -484,19 +482,18 @@ int TPpContext::eval(int token, int precedence, int& res, bool& err, TPpToken* p return token; } else { if (macroReturn == -1) { - if (parseContext.profile == EEsProfile) { + if (! shortCircuit && parseContext.profile == EEsProfile) { + const char* message = "undefined macro in expression not allowed in es profile"; + const char* name = GetAtomString(ppToken->atom); if (parseContext.messages & EShMsgRelaxedErrors) - parseContext.warn(ppToken->loc, "undefined macro in expression not allowed in es profile", "preprocessor evaluation", ""); - else { - parseContext.error(ppToken->loc, "undefined macro in expression", "preprocessor evaluation", ""); - - err = true; - } + parseContext.warn(ppToken->loc, message, "preprocessor evaluation", name); + else + parseContext.error(ppToken->loc, message, "preprocessor evaluation", name); } } token = currentInput->scan(this, currentInput, ppToken); - return eval(token, precedence, res, err, ppToken); + return eval(token, precedence, shortCircuit, res, err, ppToken); } } } else if (token == CPP_INTCONSTANT) { @@ -504,7 +501,7 @@ int TPpContext::eval(int token, int precedence, int& res, bool& err, TPpToken* p token = currentInput->scan(this, currentInput, ppToken); } else if (token == '(') { token = currentInput->scan(this, currentInput, ppToken); - token = eval(token, MIN_PRECEDENCE, res, err, ppToken); + token = eval(token, MIN_PRECEDENCE, shortCircuit, res, err, ppToken); if (! err) { if (token != ')') { parseContext.error(ppToken->loc, "expected ')'", "preprocessor evaluation", ""); @@ -516,14 +513,15 @@ int TPpContext::eval(int token, int precedence, int& res, bool& err, TPpToken* p token = currentInput->scan(this, currentInput, ppToken); } } else { - for (i = ALEN(unop) - 1; i >= 0; i--) { - if (unop[i].token == token) + int op; + for (op = NUM_ELEMENTS(unop) - 1; op >= 0; op--) { + if (unop[op].token == token) break; } - if (i >= 0) { + if (op >= 0) { token = currentInput->scan(this, currentInput, ppToken); - token = eval(token, UNARY, res, err, ppToken); - res = unop[i].op(res); + token = eval(token, UNARY, shortCircuit, res, err, ppToken); + res = unop[op].op(res); } else { parseContext.error(ppToken->loc, "bad expression", "preprocessor evaluation", ""); err = true; @@ -535,16 +533,26 @@ int TPpContext::eval(int token, int precedence, int& res, bool& err, TPpToken* p while (! err) { if (token == ')' || token == '\n') break; - for (i = ALEN(binop) - 1; i >= 0; i--) { - if (binop[i].token == token) + int op; + for (op = NUM_ELEMENTS(binop) - 1; op >= 0; op--) { + if (binop[op].token == token) break; } - if (i < 0 || binop[i].precedence <= precedence) + if (op < 0 || binop[op].precedence <= precedence) break; - val = res; + int leftSide = res; + + // Setup short-circuiting, needed for ES, unless already in a short circuit. + // (Once in a short-circuit, can't turn off again, until that whole subexpression is done. + if (! shortCircuit) { + if ((token == CPP_OR_OP && leftSide == 1) || + (token == CPP_AND_OP && leftSide == 0)) + shortCircuit = true; + } + token = currentInput->scan(this, currentInput, ppToken); - token = eval(token, binop[i].precedence, res, err, ppToken); - res = binop[i].op(val, res); + token = eval(token, binop[op].precedence, shortCircuit, res, err, ppToken); + res = binop[op].op(leftSide, res); } return token; @@ -563,7 +571,7 @@ int TPpContext::CPPif(TPpToken* ppToken) } int res = 0; bool err = false; - token = eval(token, MIN_PRECEDENCE, res, err, ppToken); + token = eval(token, MIN_PRECEDENCE, false, res, err, ppToken); token = extraTokenCheck(ifAtom, ppToken, token); if (!res && !err) token = CPPelse(1, ppToken); @@ -612,7 +620,7 @@ int TPpContext::CPPline(TPpToken* ppToken) int lineRes = 0; bool lineErr = false; - token = eval(token, MIN_PRECEDENCE, lineRes, lineErr, ppToken); + token = eval(token, MIN_PRECEDENCE, false, lineRes, lineErr, ppToken); if (! lineErr) { if (token == '\n') ++lineRes; @@ -620,7 +628,7 @@ int TPpContext::CPPline(TPpToken* ppToken) if (token != '\n') { int fileRes = 0; bool fileErr = false; - token = eval(token, MIN_PRECEDENCE, fileRes, fileErr, ppToken); + token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken); if (! fileErr) parseContext.setCurrentString(fileRes); } diff --git a/glslang/MachineIndependent/preprocessor/PpContext.h b/glslang/MachineIndependent/preprocessor/PpContext.h index 32691780..4fc2c87f 100644 --- a/glslang/MachineIndependent/preprocessor/PpContext.h +++ b/glslang/MachineIndependent/preprocessor/PpContext.h @@ -246,7 +246,7 @@ protected: int CPPundef(TPpToken * ppToken); int CPPelse(int matchelse, TPpToken * ppToken); int extraTokenCheck(int atom, TPpToken* ppToken, int token); - int eval(int token, int precedence, int& res, bool& err, TPpToken * ppToken); + int eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken * ppToken); int CPPif (TPpToken * ppToken); int CPPifdef(int defined, TPpToken * ppToken); int CPPline(TPpToken * ppToken);