Check for multiple default cases in switch or select.
authorIan Lance Taylor <ian@gcc.gnu.org>
Tue, 4 Jan 2011 19:34:32 +0000 (19:34 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 4 Jan 2011 19:34:32 +0000 (19:34 +0000)
From-SVN: r168481

gcc/go/gofrontend/parse.cc
gcc/go/gofrontend/parse.h

index f4b01be8c93452c88fc71e6e804194fb5950c1b7..13374f40bcc9fd9db7264a0ecfbbae1a3f53b828 100644 (file)
@@ -3825,6 +3825,7 @@ Parse::expr_switch_body(const Label* label, Expression* switch_val,
   this->push_break_statement(statement, label);
 
   Case_clauses* case_clauses = new Case_clauses();
+  bool saw_default = false;
   while (!this->peek_token()->is_op(OPERATOR_RCURLY))
     {
       if (this->peek_token()->is_eof())
@@ -3833,7 +3834,7 @@ Parse::expr_switch_body(const Label* label, Expression* switch_val,
            error_at(this->location(), "missing %<}%>");
          return NULL;
        }
-      this->expr_case_clause(case_clauses);
+      this->expr_case_clause(case_clauses, &saw_default);
     }
   this->advance_token();
 
@@ -3848,7 +3849,7 @@ Parse::expr_switch_body(const Label* label, Expression* switch_val,
 // FallthroughStat = "fallthrough" .
 
 void
-Parse::expr_case_clause(Case_clauses* clauses)
+Parse::expr_case_clause(Case_clauses* clauses, bool* saw_default)
 {
   source_location location = this->location();
 
@@ -3880,6 +3881,16 @@ Parse::expr_case_clause(Case_clauses* clauses)
        this->advance_token();
     }
 
+  if (is_default)
+    {
+      if (*saw_default)
+       {
+         error_at(location, "multiple defaults in switch");
+         return;
+       }
+      *saw_default = true;
+    }
+
   if (is_default || vals != NULL)
     clauses->add(vals, is_default, statements, is_fallthrough, location);
 }
@@ -3936,6 +3947,7 @@ Parse::type_switch_body(const Label* label, const Type_switch& type_switch,
   this->push_break_statement(statement, label);
 
   Type_case_clauses* case_clauses = new Type_case_clauses();
+  bool saw_default = false;
   while (!this->peek_token()->is_op(OPERATOR_RCURLY))
     {
       if (this->peek_token()->is_eof())
@@ -3943,7 +3955,7 @@ Parse::type_switch_body(const Label* label, const Type_switch& type_switch,
          error_at(this->location(), "missing %<}%>");
          return NULL;
        }
-      this->type_case_clause(switch_no, case_clauses);
+      this->type_case_clause(switch_no, case_clauses, &saw_default);
     }
   this->advance_token();
 
@@ -3957,7 +3969,8 @@ Parse::type_switch_body(const Label* label, const Type_switch& type_switch,
 // TypeCaseClause  = TypeSwitchCase ":" [ StatementList ] .
 
 void
-Parse::type_case_clause(Named_object* switch_no, Type_case_clauses* clauses)
+Parse::type_case_clause(Named_object* switch_no, Type_case_clauses* clauses,
+                       bool* saw_default)
 {
   source_location location = this->location();
 
@@ -4000,6 +4013,12 @@ Parse::type_case_clause(Named_object* switch_no, Type_case_clauses* clauses)
   if (is_default)
     {
       gcc_assert(types.empty());
+      if (*saw_default)
+       {
+         error_at(location, "multiple defaults in type switch");
+         return;
+       }
+      *saw_default = true;
       clauses->add(NULL, false, true, statements, location);
     }
   else if (!types.empty())
@@ -4076,6 +4095,7 @@ Parse::select_stat(const Label* label)
   this->push_break_statement(statement, label);
 
   Select_clauses* select_clauses = new Select_clauses();
+  bool saw_default = false;
   while (!this->peek_token()->is_op(OPERATOR_RCURLY))
     {
       if (this->peek_token()->is_eof())
@@ -4083,7 +4103,7 @@ Parse::select_stat(const Label* label)
          error_at(this->location(), "expected %<}%>");
          return;
        }
-      this->comm_clause(select_clauses);
+      this->comm_clause(select_clauses, &saw_default);
     }
 
   this->advance_token();
@@ -4098,7 +4118,7 @@ Parse::select_stat(const Label* label)
 // CommClause = CommCase [ StatementList ] .
 
 void
-Parse::comm_clause(Select_clauses* clauses)
+Parse::comm_clause(Select_clauses* clauses, bool* saw_default)
 {
   source_location location = this->location();
   bool is_send = false;
@@ -4130,6 +4150,16 @@ Parse::comm_clause(Select_clauses* clauses)
       statements = this->gogo_->finish_block(this->location());
     }
 
+  if (is_default)
+    {
+      if (*saw_default)
+       {
+         error_at(location, "multiple defaults in select");
+         return;
+       }
+      *saw_default = true;
+    }
+
   if (got_case)
     clauses->add(is_send, channel, val, var, is_default, statements, location);
 }
index 1fa931957553b93e2cbc3ac109e9182dc3d99f57..65f15860b4401cc69110a149e39d322b506b21b9 100644 (file)
@@ -238,14 +238,14 @@ class Parse
   void if_stat();
   void switch_stat(const Label*);
   Statement* expr_switch_body(const Label*, Expression*, source_location);
-  void expr_case_clause(Case_clauses*);
+  void expr_case_clause(Case_clauses*, bool* saw_default);
   Expression_list* expr_switch_case(bool*);
   Statement* type_switch_body(const Label*, const Type_switch&,
                              source_location);
-  void type_case_clause(Named_object*, Type_case_clauses*);
+  void type_case_clause(Named_object*, Type_case_clauses*, bool* saw_default);
   void type_switch_case(std::vector<Type*>*, bool*);
   void select_stat(const Label*);
-  void comm_clause(Select_clauses*);
+  void comm_clause(Select_clauses*, bool* saw_default);
   bool comm_case(bool*, Expression**, Expression**, std::string*, bool*);
   bool send_or_recv_expr(bool*, Expression**, Expression**, std::string*);
   void for_stat(const Label*);