glsl: Track variable usage, use that to enforce semantics

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.
This commit is contained in:
Ian Romanick
2011-01-07 18:34:58 -08:00
parent c3f000b392
commit bd33055ef4
3 changed files with 26 additions and 2 deletions

View File

@@ -1623,6 +1623,7 @@ ast_expression::hir(exec_list *instructions,
result = new(ctx) ir_dereference_variable(var); result = new(ctx) ir_dereference_variable(var);
if (var != NULL) { if (var != NULL) {
var->used = true;
type = result->type; type = result->type;
} else { } else {
_mesa_glsl_error(& loc, state, "`%s' undeclared", _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, struct _mesa_glsl_parse_state *state,
YYLTYPE *loc) YYLTYPE *loc)
{ {
if (qual->flags.q.invariant) if (qual->flags.q.invariant) {
var->invariant = 1; 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. */ /* FINISHME: Mark 'in' variables at global scope as read-only. */
if (qual->flags.q.constant || qual->flags.q.attribute 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, _mesa_glsl_error(& loc, state,
"`%s' cannot be marked invariant, fragment shader " "`%s' cannot be marked invariant, fragment shader "
"inputs only\n", decl->identifier); "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 { } else {
earlier->invariant = true; earlier->invariant = true;
} }

View File

@@ -1325,6 +1325,7 @@ ir_variable::ir_variable(const struct glsl_type *type, const char *name,
this->constant_value = NULL; this->constant_value = NULL;
this->origin_upper_left = false; this->origin_upper_left = false;
this->pixel_center_integer = false; this->pixel_center_integer = false;
this->used = false;
if (type && type->base_type == GLSL_TYPE_SAMPLER) if (type && type->base_type == GLSL_TYPE_SAMPLER)
this->read_only = true; this->read_only = true;

View File

@@ -294,6 +294,15 @@ public:
unsigned centroid:1; unsigned centroid:1;
unsigned invariant: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. * Storage class of the variable.
* *