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
This commit is contained in:
John Kessenich 2013-12-06 18:19:22 +00:00
parent e28beee891
commit 7fc3669195
5 changed files with 117 additions and 38 deletions

View File

@ -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!

View File

@ -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

View File

@ -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"

View File

@ -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);
}

View File

@ -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);