glsl: Throw an error when faced with a duplicated switch() case label.
authorEric Anholt <eric@anholt.net>
Mon, 30 Jan 2012 16:50:14 +0000 (08:50 -0800)
committerEric Anholt <eric@anholt.net>
Fri, 3 Feb 2012 10:07:02 +0000 (11:07 +0100)
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>
src/glsl/ast_to_hir.cpp
src/glsl/glsl_parser_extras.h

index 28aff397757aa483573d97fc1478b236376c8c97..4f328ad8f46df519e5ea5f992d3c27827fb300ec 100644 (file)
@@ -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 =
index 35d1e3aee26ea90ebf665aaffb8ce66a0013a2d6..d5d5101a8208c1975e59757a093501fa3d01428b 100644 (file)
@@ -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, ...
 };