summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Anholt <eric@anholt.net>2012-01-30 08:50:14 -0800
committerIan Romanick <ian.d.romanick@intel.com>2012-02-07 10:26:17 -0800
commit83075bd0fe1fa4519f40edde1f9bc70967ee03a9 (patch)
treeada99f2bf5b17049a94281aa77fabad41d065e3c
parentd799a7b585225441b5a424fbd3de8b719d0ada6e (diff)
glsl: Throw an error when faced with a duplicated switch() case label.
The error message I chose matches gcc's error. Fixes piglit switch-case-duplicated.vert. NOTE: This is a candidate for the 8.0 branch. Reviewed-by: Ian Romanick <ian.d.romanick@intel.com> (cherry picked from commit 140632190cf41e6a035ca199b181091d4ed46986)
-rw-r--r--src/glsl/ast_to_hir.cpp23
-rw-r--r--src/glsl/glsl_parser_extras.h4
2 files changed, 27 insertions, 0 deletions
diff --git a/src/glsl/ast_to_hir.cpp b/src/glsl/ast_to_hir.cpp
index 28aff39775..4f328ad8f4 100644
--- a/src/glsl/ast_to_hir.cpp
+++ b/src/glsl/ast_to_hir.cpp
@@ -54,6 +54,7 @@
#include "glsl_parser_extras.h"
#include "ast.h"
#include "glsl_types.h"
+#include "program/hash_table.h"
#include "ir.h"
void
@@ -3534,6 +3535,8 @@ ast_switch_statement::hir(exec_list *instructions,
state->switch_state.is_switch_innermost = true;
state->switch_state.switch_nesting_ast = this;
+ state->switch_state.labels_ht = hash_table_ctor(0, hash_table_pointer_hash,
+ hash_table_pointer_compare);
/* Initalize is_fallthru state to false.
*/
@@ -3572,6 +3575,8 @@ ast_switch_statement::hir(exec_list *instructions,
*/
body->hir(instructions, state);
+ hash_table_dtor(state->switch_state.labels_ht);
+
state->switch_state = saved;
/* Switch statements do not have r-values.
@@ -3709,6 +3714,24 @@ ast_switch_statement::hir(exec_list *instructions,
/* Stuff a dummy value in to allow processing to continue. */
label_const = new(ctx) ir_constant(0);
+ } else {
+ ast_expression *previous_label = (ast_expression *)
+ hash_table_find(state->switch_state.labels_ht,
+ (void *)(uintptr_t)label_const->value.u[0]);
+
+ if (previous_label) {
+ YYLTYPE loc = this->test_value->get_location();
+ _mesa_glsl_error(& loc, state,
+ "duplicate case value");
+
+ loc = previous_label->get_location();
+ _mesa_glsl_error(& loc, state,
+ "this is the previous case label");
+ } else {
+ hash_table_insert(state->switch_state.labels_ht,
+ this->test_value,
+ (void *)(uintptr_t)label_const->value.u[0]);
+ }
}
ir_dereference_variable *deref_test_var =
diff --git a/src/glsl/glsl_parser_extras.h b/src/glsl/glsl_parser_extras.h
index 35d1e3aee2..d5d5101a82 100644
--- a/src/glsl/glsl_parser_extras.h
+++ b/src/glsl/glsl_parser_extras.h
@@ -48,6 +48,10 @@ struct glsl_switch_state {
ir_variable *is_fallthru_var;
ir_variable *is_break_var;
class ast_switch_statement *switch_nesting_ast;
+
+ /** Table of constant values already used in case labels */
+ struct hash_table *labels_ht;
+
bool is_switch_innermost; // if switch stmt is closest to break, ...
};