glsl: Track variable usage, use that to enforce semantics
authorIan Romanick <ian.d.romanick@intel.com>
Sat, 8 Jan 2011 02:34:58 +0000 (18:34 -0800)
committerIan Romanick <ian.d.romanick@intel.com>
Wed, 12 Jan 2011 22:30:31 +0000 (14:30 -0800)
In particular, variables cannot be redeclared invariant after being
used.

Fixes piglit test invariant-05.vert and bugzilla #29164.

NOTE: This is a candidate for the 7.9 and 7.10 branches.

src/glsl/ast_to_hir.cpp
src/glsl/ir.cpp
src/glsl/ir.h

index c4bd7e64e27f14ccce1214fabdfef0293ffc47ef..a833be18f315f1e51aa0210a1f66072ddffb84a1 100644 (file)
@@ -1623,6 +1623,7 @@ ast_expression::hir(exec_list *instructions,
       result = new(ctx) ir_dereference_variable(var);
 
       if (var != NULL) {
+        var->used = true;
         type = result->type;
       } else {
         _mesa_glsl_error(& loc, state, "`%s' undeclared",
@@ -1797,8 +1798,16 @@ apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
                                 struct _mesa_glsl_parse_state *state,
                                 YYLTYPE *loc)
 {
-   if (qual->flags.q.invariant)
-      var->invariant = 1;
+   if (qual->flags.q.invariant) {
+      if (var->used) {
+        _mesa_glsl_error(loc, state,
+                         "variable `%s' may not be redeclared "
+                         "`invariant' after being used",
+                         var->name);
+      } else {
+        var->invariant = 1;
+      }
+   }
 
    /* FINISHME: Mark 'in' variables at global scope as read-only. */
    if (qual->flags.q.constant || qual->flags.q.attribute
@@ -2005,6 +2014,11 @@ ast_declarator_list::hir(exec_list *instructions,
            _mesa_glsl_error(& loc, state,
                             "`%s' cannot be marked invariant, fragment shader "
                             "inputs only\n", decl->identifier);
+        } else if (earlier->used) {
+           _mesa_glsl_error(& loc, state,
+                            "variable `%s' may not be redeclared "
+                            "`invariant' after being used",
+                            earlier->name);
         } else {
            earlier->invariant = true;
         }
index 742dd41b9f478c9d1440a91e2a0a3e2066d1562a..460d43b02e1361f2532ea3db63ebdb794d0d54b4 100644 (file)
@@ -1325,6 +1325,7 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name,
    this->constant_value = NULL;
    this->origin_upper_left = false;
    this->pixel_center_integer = false;
+   this->used = false;
 
    if (type && type->base_type == GLSL_TYPE_SAMPLER)
       this->read_only = true;
index 9668c9439adfd7c5ed1f684da227c60b70ae6e34..57e89f0f6bff7156367cfd8ae415a3140441e059 100644 (file)
@@ -294,6 +294,15 @@ public:
    unsigned centroid:1;
    unsigned invariant:1;
 
+   /**
+    * Has this variable been used for reading or writing?
+    *
+    * Several GLSL semantic checks require knowledge of whether or not a
+    * variable has been used.  For example, it is an error to redeclare a
+    * variable as invariant after it has been used.
+    */
+   unsigned used:1;
+
    /**
     * Storage class of the variable.
     *