summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/glsl/glcpp/glcpp-parse.y106
-rw-r--r--src/glsl/glcpp/glcpp.h7
-rw-r--r--src/glsl/glcpp/tests/125-es-short-circuit-undefined.c27
-rw-r--r--src/glsl/glcpp/tests/125-es-short-circuit-undefined.c.expected30
4 files changed, 140 insertions, 30 deletions
diff --git a/src/glsl/glcpp/glcpp-parse.y b/src/glsl/glcpp/glcpp-parse.y
index 82e310270d6..68e4ace012e 100644
--- a/src/glsl/glcpp/glcpp-parse.y
+++ b/src/glsl/glcpp/glcpp-parse.y
@@ -166,7 +166,8 @@ add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
%expect 0
%token COMMA_FINAL DEFINED ELIF_EXPANDED HASH HASH_DEFINE FUNC_IDENTIFIER OBJ_IDENTIFIER HASH_ELIF HASH_ELSE HASH_ENDIF HASH_IF HASH_IFDEF HASH_IFNDEF HASH_LINE HASH_UNDEF HASH_VERSION IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING LINE_EXPANDED NEWLINE OTHER PLACEHOLDER SPACE
%token PASTE
-%type <ival> expression INTEGER operator SPACE integer_constant
+%type <ival> INTEGER operator SPACE integer_constant
+%type <expression_value> expression
%type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER
%type <string_list> identifier_list
%type <token> preprocessing_token conditional_token
@@ -216,10 +217,14 @@ line:
expanded_line:
IF_EXPANDED expression NEWLINE {
- _glcpp_parser_skip_stack_push_if (parser, & @1, $2);
+ if (parser->is_gles && $2.has_undefined)
+ glcpp_error(& @1, parser, "undefined macro in expression (illegal in GLES)");
+ _glcpp_parser_skip_stack_push_if (parser, & @1, $2.value);
}
| ELIF_EXPANDED expression NEWLINE {
- _glcpp_parser_skip_stack_change_if (parser, & @1, "elif", $2);
+ if (parser->is_gles && $2.has_undefined)
+ glcpp_error(& @1, parser, "undefined macro in expression (illegal in GLES)");
+ _glcpp_parser_skip_stack_change_if (parser, & @1, "elif", $2.value);
}
| LINE_EXPANDED integer_constant NEWLINE {
parser->has_new_line_number = 1;
@@ -412,87 +417,128 @@ integer_constant:
}
expression:
- integer_constant
+ integer_constant {
+ $$.value = $1;
+ $$.has_undefined = false;
+ }
| IDENTIFIER {
+ $$.value = 0;
if (parser->is_gles)
- glcpp_error(& @1, parser, "undefined macro %s in expression (illegal in GLES)", $1);
- $$ = 0;
+ $$.has_undefined = true;
+ else
+ $$.has_undefined = false;
}
| expression OR expression {
- $$ = $1 || $3;
+ $$.value = $1.value || $3.value;
+
+ /* Short-circuit: Only flag undefined from right side
+ * if left side evaluates to false.
+ */
+ if ($1.value)
+ $$.has_undefined = $1.has_undefined;
+ else
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression AND expression {
- $$ = $1 && $3;
+ $$.value = $1.value && $3.value;
+
+ /* Short-circuit: Only flag undefined from right-side
+ * if left side evaluates to true.
+ */
+ if ($1.value)
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
+ else
+ $$.has_undefined = $1.has_undefined;
}
| expression '|' expression {
- $$ = $1 | $3;
+ $$.value = $1.value | $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression '^' expression {
- $$ = $1 ^ $3;
+ $$.value = $1.value ^ $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression '&' expression {
- $$ = $1 & $3;
+ $$.value = $1.value & $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression NOT_EQUAL expression {
- $$ = $1 != $3;
+ $$.value = $1.value != $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression EQUAL expression {
- $$ = $1 == $3;
+ $$.value = $1.value == $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression GREATER_OR_EQUAL expression {
- $$ = $1 >= $3;
+ $$.value = $1.value >= $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression LESS_OR_EQUAL expression {
- $$ = $1 <= $3;
+ $$.value = $1.value <= $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression '>' expression {
- $$ = $1 > $3;
+ $$.value = $1.value > $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression '<' expression {
- $$ = $1 < $3;
+ $$.value = $1.value < $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression RIGHT_SHIFT expression {
- $$ = $1 >> $3;
+ $$.value = $1.value >> $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression LEFT_SHIFT expression {
- $$ = $1 << $3;
+ $$.value = $1.value << $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression '-' expression {
- $$ = $1 - $3;
+ $$.value = $1.value - $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression '+' expression {
- $$ = $1 + $3;
+ $$.value = $1.value + $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression '%' expression {
- if ($3 == 0) {
+ if ($3.value == 0) {
yyerror (& @1, parser,
"zero modulus in preprocessor directive");
} else {
- $$ = $1 % $3;
+ $$.value = $1.value % $3.value;
}
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression '/' expression {
- if ($3 == 0) {
+ if ($3.value == 0) {
yyerror (& @1, parser,
"division by 0 in preprocessor directive");
} else {
- $$ = $1 / $3;
+ $$.value = $1.value / $3.value;
}
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| expression '*' expression {
- $$ = $1 * $3;
+ $$.value = $1.value * $3.value;
+ $$.has_undefined = $1.has_undefined || $3.has_undefined;
}
| '!' expression %prec UNARY {
- $$ = ! $2;
+ $$.value = ! $2.value;
+ $$.has_undefined = $2.has_undefined;
}
| '~' expression %prec UNARY {
- $$ = ~ $2;
+ $$.value = ~ $2.value;
+ $$.has_undefined = $2.has_undefined;
}
| '-' expression %prec UNARY {
- $$ = - $2;
+ $$.value = - $2.value;
+ $$.has_undefined = $2.has_undefined;
}
| '+' expression %prec UNARY {
- $$ = + $2;
+ $$.value = + $2.value;
+ $$.has_undefined = $2.has_undefined;
}
| '(' expression ')' {
$$ = $2;
diff --git a/src/glsl/glcpp/glcpp.h b/src/glsl/glcpp/glcpp.h
index b2654ffbed2..9783210b708 100644
--- a/src/glsl/glcpp/glcpp.h
+++ b/src/glsl/glcpp/glcpp.h
@@ -37,6 +37,12 @@
/* Some data types used for parser values. */
+typedef struct expression_value {
+ intmax_t value;
+ bool has_undefined;
+} expression_value_t;
+
+
typedef struct string_node {
const char *str;
struct string_node *next;
@@ -53,6 +59,7 @@ typedef struct token_list token_list_t;
typedef union YYSTYPE
{
intmax_t ival;
+ expression_value_t expression_value;
char *str;
string_list_t *string_list;
token_t *token;
diff --git a/src/glsl/glcpp/tests/125-es-short-circuit-undefined.c b/src/glsl/glcpp/tests/125-es-short-circuit-undefined.c
new file mode 100644
index 00000000000..4ee29f6d93f
--- /dev/null
+++ b/src/glsl/glcpp/tests/125-es-short-circuit-undefined.c
@@ -0,0 +1,27 @@
+/* For GLSL in OpenGL ES, an undefined macro appearing in an #if or #elif
+ * expression, (other than as an argument to defined) is an error.
+ *
+ * Except in the case of a short-circuiting && or || operator, where the
+ * specification explicitly mandates that there be no error.
+ */
+#version 300 es
+
+/* These yield errors */
+#if NOT_DEFINED
+#endif
+
+#if 0
+#elif ALSO_NOT_DEFINED
+#endif
+
+/* But these yield no errors */
+#if 1 || STILL_NOT_DEFINED
+Success
+#endif
+
+#if 0
+#elif 0 && WILL_ANYONE_DEFINE_ANYTHING
+#else
+More success
+#endif
+
diff --git a/src/glsl/glcpp/tests/125-es-short-circuit-undefined.c.expected b/src/glsl/glcpp/tests/125-es-short-circuit-undefined.c.expected
new file mode 100644
index 00000000000..a52dae8f76a
--- /dev/null
+++ b/src/glsl/glcpp/tests/125-es-short-circuit-undefined.c.expected
@@ -0,0 +1,30 @@
+0:10(16): preprocessor error: undefined macro in expression (illegal in GLES)
+0:14(23): preprocessor error: undefined macro in expression (illegal in GLES)
+
+
+
+
+
+
+#version 300 es
+
+
+
+
+
+
+
+
+
+
+
+Success
+
+
+
+
+
+More success
+
+
+