local compile-time const values are now created as globals, thus they're now subject...
authorWolfgang Bumiller <wry.git@bumiller.com>
Sat, 24 May 2014 17:13:49 +0000 (19:13 +0200)
committerWolfgang Bumiller <wry.git@bumiller.com>
Sat, 24 May 2014 17:13:49 +0000 (19:13 +0200)
parser.c
tests/inexact-local.qc [new file with mode: 0644]
tests/inexact-local.tmpl [new file with mode: 0644]

index 5666a82..fc02cac 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -5146,6 +5146,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
     bool      wasarray  = false;
 
     ast_member *me[3] = { NULL, NULL, NULL };
+    ast_member *last_me[3] = { NULL, NULL, NULL };
 
     if (!localblock && is_static)
         parseerror(parser, "`static` qualifier is not supported in global scope");
@@ -5609,6 +5610,7 @@ static bool parse_variable(parser_t *parser, ast_block *localblock, bool nofield
                 }
             }
         }
+        memcpy(last_me, me, sizeof(me));
         me[0] = me[1] = me[2] = NULL;
         cleanvar = false;
         /* Part 2.2
@@ -5816,15 +5818,44 @@ skipvar:
         } else {
             ast_expression *cexp;
             ast_value      *cval;
+            bool            folded_const = false;
 
             cexp = parse_expression_leave(parser, true, false, false);
             if (!cexp)
                 break;
+            cval = ast_istype(cexp, ast_value) ? (ast_value*)cexp : NULL;
 
-            if (!localblock || is_static) {
-                cval = (ast_value*)cexp;
+            /* deal with foldable constants: */
+            if (localblock &&
+                var->cvq == CV_CONST && cval && cval->hasvalue && cval->cvq == CV_CONST && !cval->isfield)
+            {
+                /* remove it from the current locals */
+                if (isvector) {
+                    for (i = 0; i < 3; ++i) {
+                        vec_pop(parser->_locals);
+                        vec_pop(localblock->collect);
+                    }
+                }
+                /* do sanity checking, this function really needs refactoring */
+                if (vec_last(parser->_locals) != (ast_expression*)var)
+                    parseerror(parser, "internal error: unexpected change in local variable handling");
+                else
+                    vec_pop(parser->_locals);
+                if (vec_last(localblock->locals) != var)
+                    parseerror(parser, "internal error: unexpected change in local variable handling (2)");
+                else
+                    vec_pop(localblock->locals);
+                /* push it to the to-be-generated globals */
+                vec_push(parser->globals, (ast_expression*)var);
+                if (isvector)
+                    for (i = 0; i < 3; ++i)
+                        vec_push(parser->globals, (ast_expression*)last_me[i]);
+                folded_const = true;
+            }
+
+            if (folded_const || !localblock || is_static) {
                 if (cval != parser->nil &&
-                    (!ast_istype(cval, ast_value) || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield))
+                    (!cval || ((!cval->hasvalue || cval->cvq != CV_CONST) && !cval->isfield))
                    )
                 {
                     parseerror(parser, "initializer is non constant");
@@ -5876,8 +5907,7 @@ skipvar:
              * const float x = <inexact>; should propagate the inexact flag
              */
             if (var->cvq == CV_CONST && var->expression.vtype == TYPE_FLOAT) {
-                cval = (ast_value*)cexp;
-                if (ast_istype(cexp, ast_value) && cval->hasvalue && cval->cvq == CV_CONST)
+                if (cval && cval->hasvalue && cval->cvq == CV_CONST)
                     var->inexact = cval->inexact;
             }
         }
diff --git a/tests/inexact-local.qc b/tests/inexact-local.qc
new file mode 100644 (file)
index 0000000..a17cccd
--- /dev/null
@@ -0,0 +1,7 @@
+void main() {
+    const float a = 1.0 / 3.0;
+    const float b = 0.33333333333;
+    if (a == b) {
+        // Should trigger warning
+    }
+}
diff --git a/tests/inexact-local.tmpl b/tests/inexact-local.tmpl
new file mode 100644 (file)
index 0000000..3917a90
--- /dev/null
@@ -0,0 +1,4 @@
+I: inexact-local.qc
+D: inexact comparisons
+T: -fail
+C: -std=gmqcc -Winexact-compares -Wall -Werror