I committed this patch to update libgo to the Go 1.4.2 release (it was
at 1.4 before).  Bootstrapped and ran testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff -r d42a0819e2eb go/gogo.cc
--- a/go/gogo.cc        Fri Feb 06 08:17:54 2015 -0800
+++ b/go/gogo.cc        Thu Mar 05 16:21:29 2015 -0800
@@ -6030,6 +6030,7 @@
   Type* type = this->type_;
   Expression* init = this->init_;
   if (this->is_type_switch_var_
+      && type != NULL
       && this->type_->is_nil_constant_as_type())
     {
       Type_guard_expression* tge = this->init_->type_guard_expression();
@@ -6103,7 +6104,9 @@
   // type here.  It will have an initializer which is a type guard.
   // We want to initialize it to the value without the type guard, and
   // use the type of that value as well.
-  if (this->is_type_switch_var_ && this->type_->is_nil_constant_as_type())
+  if (this->is_type_switch_var_
+      && this->type_ != NULL
+      && this->type_->is_nil_constant_as_type())
     {
       Type_guard_expression* tge = this->init_->type_guard_expression();
       go_assert(tge != NULL);
diff -r d42a0819e2eb go/parse.cc
--- a/go/parse.cc       Fri Feb 06 08:17:54 2015 -0800
+++ b/go/parse.cc       Thu Mar 05 16:21:29 2015 -0800
@@ -50,8 +50,7 @@
     break_stack_(NULL),
     continue_stack_(NULL),
     iota_(0),
-    enclosing_vars_(),
-    type_switch_vars_()
+    enclosing_vars_()
 {
 }
 
@@ -4596,32 +4595,33 @@
 Parse::type_switch_body(Label* label, const Type_switch& type_switch,
                        Location location)
 {
-  Named_object* switch_no = NULL;
-  if (!type_switch.name.empty())
-    {
-      if (Gogo::is_sink_name(type_switch.name))
-       error_at(type_switch.location,
-                "no new variables on left side of %<:=%>");
+  Expression* init = type_switch.expr;
+  std::string var_name = type_switch.name;
+  if (!var_name.empty())
+    {
+      if (Gogo::is_sink_name(var_name))
+        {
+          error_at(type_switch.location,
+                   "no new variables on left side of %<:=%>");
+          var_name.clear();
+        }
       else
        {
-         Variable* switch_var = new Variable(NULL, type_switch.expr, false,
-                                             false, false,
-                                             type_switch.location);
-         switch_no = this->gogo_->add_variable(type_switch.name, switch_var);
+          Location loc = type_switch.location;
+         Temporary_statement* switch_temp =
+              Statement::make_temporary(NULL, init, loc);
+         this->gogo_->add_statement(switch_temp);
+          init = Expression::make_temporary_reference(switch_temp, loc);
        }
     }
 
   Type_switch_statement* statement =
-    Statement::make_type_switch_statement(switch_no,
-                                         (switch_no == NULL
-                                          ? type_switch.expr
-                                          : NULL),
-                                         location);
-
+      Statement::make_type_switch_statement(var_name, init, location);
   this->push_break_statement(statement, label);
 
   Type_case_clauses* case_clauses = new Type_case_clauses();
   bool saw_default = false;
+  std::vector<Named_object*> implicit_vars;
   while (!this->peek_token()->is_op(OPERATOR_RCURLY))
     {
       if (this->peek_token()->is_eof())
@@ -4629,7 +4629,8 @@
          error_at(this->location(), "missing %<}%>");
          return NULL;
        }
-      this->type_case_clause(switch_no, case_clauses, &saw_default);
+      this->type_case_clause(var_name, init, case_clauses, &saw_default,
+                             &implicit_vars);
     }
   this->advance_token();
 
@@ -4637,14 +4638,36 @@
 
   this->pop_break_statement();
 
+  // If there is a type switch variable implicitly declared in each case 
clause,
+  // check that it is used in at least one of the cases.
+  if (!var_name.empty())
+    {
+      bool used = false;
+      for (std::vector<Named_object*>::iterator p = implicit_vars.begin();
+          p != implicit_vars.end();
+          ++p)
+       {
+         if ((*p)->var_value()->is_used())
+           {
+             used = true;
+             break;
+           }
+       }
+      if (!used)
+       error_at(type_switch.location, "%qs declared and not used",
+                Gogo::message_name(var_name).c_str());
+    }
   return statement;
 }
 
 // TypeCaseClause  = TypeSwitchCase ":" [ StatementList ] .
+// IMPLICIT_VARS is the list of variables implicitly declared for each type
+// case if there is a type switch variable declared.
 
 void
-Parse::type_case_clause(Named_object* switch_no, Type_case_clauses* clauses,
-                       bool* saw_default)
+Parse::type_case_clause(const std::string& var_name, Expression* init,
+                        Type_case_clauses* clauses, bool* saw_default,
+                       std::vector<Named_object*>* implicit_vars)
 {
   Location location = this->location();
 
@@ -4661,24 +4684,21 @@
   if (this->statement_list_may_start_here())
     {
       this->gogo_->start_block(this->location());
-      if (switch_no != NULL && types.size() == 1)
+      if (!var_name.empty())
        {
-         Type* type = types.front();
-         Expression* init = Expression::make_var_reference(switch_no,
-                                                           location);
-         init = Expression::make_type_guard(init, type, location);
+         Type* type = NULL;
+          Location var_loc = init->location();
+         if (types.size() == 1)
+           {
+             type = types.front();
+             init = Expression::make_type_guard(init, type, location);
+           }
+
          Variable* v = new Variable(type, init, false, false, false,
-                                    location);
+                                    var_loc);
+         v->set_is_used();
          v->set_is_type_switch_var();
-         Named_object* no = this->gogo_->add_variable(switch_no->name(), v);
-
-         // We don't want to issue an error if the compiler
-         // introduced special variable is not used.  Instead we want
-         // to issue an error if the variable defined by the switch
-         // is not used.  That is handled via type_switch_vars_ and
-         // Parse::mark_var_used.
-         v->set_is_used();
-         this->type_switch_vars_[no] = switch_no;
+         implicit_vars->push_back(this->gogo_->add_variable(var_name, v));
        }
       this->statement_list();
       statements = this->gogo_->finish_block(this->location());
@@ -5752,15 +5772,5 @@
 Parse::mark_var_used(Named_object* no)
 {
   if (no->is_variable())
-    {
-      no->var_value()->set_is_used();
-
-      // When a type switch uses := to define a variable, then for
-      // each case with a single type we introduce a new variable with
-      // the appropriate type.  When we do, if the newly introduced
-      // variable is used, then the type switch variable is used.
-      Type_switch_vars::iterator p = this->type_switch_vars_.find(no);
-      if (p != this->type_switch_vars_.end())
-       p->second->var_value()->set_is_used();
-    }
+    no->var_value()->set_is_used();
 }
diff -r d42a0819e2eb go/parse.h
--- a/go/parse.h        Fri Feb 06 08:17:54 2015 -0800
+++ b/go/parse.h        Thu Mar 05 16:21:29 2015 -0800
@@ -156,11 +156,6 @@
   // break or continue statement with no label.
   typedef std::vector<std::pair<Statement*, Label*> > Bc_stack;
 
-  // Map from type switch variables to the variables they mask, so
-  // that a use of the type switch variable can become a use of the
-  // real variable.
-  typedef Unordered_map(Named_object*, Named_object*) Type_switch_vars;
-
   // Parser nonterminals.
   void identifier_list(Typed_identifier_list*);
   Expression_list* expression_list(Expression*, bool may_be_sink,
@@ -259,7 +254,8 @@
   void expr_case_clause(Case_clauses*, bool* saw_default);
   Expression_list* expr_switch_case(bool*);
   Statement* type_switch_body(Label*, const Type_switch&, Location);
-  void type_case_clause(Named_object*, Type_case_clauses*, bool* saw_default);
+  void type_case_clause(const std::string&, Expression*, Type_case_clauses*,
+                        bool* saw_default, std::vector<Named_object*>*);
   void type_switch_case(std::vector<Type*>*, bool*);
   void select_stat(Label*);
   void comm_clause(Select_clauses*, bool* saw_default);
@@ -327,8 +323,6 @@
   // References from the local function to variables defined in
   // enclosing functions.
   Enclosing_vars enclosing_vars_;
-  // Map from type switch variables to real variables.
-  Type_switch_vars type_switch_vars_;
 };
 
 
diff -r d42a0819e2eb go/statements.cc
--- a/go/statements.cc  Fri Feb 06 08:17:54 2015 -0800
+++ b/go/statements.cc  Thu Mar 05 16:21:29 2015 -0800
@@ -4279,11 +4279,8 @@
 int
 Type_switch_statement::do_traverse(Traverse* traverse)
 {
-  if (this->var_ == NULL)
-    {
-      if (this->traverse_expression(traverse, &this->expr_) == TRAVERSE_EXIT)
-       return TRAVERSE_EXIT;
-    }
+  if (this->traverse_expression(traverse, &this->expr_) == TRAVERSE_EXIT)
+    return TRAVERSE_EXIT;
   if (this->clauses_ != NULL)
     return this->clauses_->traverse(traverse);
   return TRAVERSE_CONTINUE;
@@ -4306,10 +4303,7 @@
 
   Block* b = new Block(enclosing, loc);
 
-  Type* val_type = (this->var_ != NULL
-                   ? this->var_->var_value()->type()
-                   : this->expr_->type());
-
+  Type* val_type = this->expr_->type();
   if (val_type->interface_type() == NULL)
     {
       if (!val_type->is_error())
@@ -4326,15 +4320,10 @@
   // descriptor_temp = ifacetype(val_temp) FIXME: This should be
   // inlined.
   bool is_empty = val_type->interface_type()->is_empty();
-  Expression* ref;
-  if (this->var_ == NULL)
-    ref = this->expr_;
-  else
-    ref = Expression::make_var_reference(this->var_, loc);
   Expression* call = Runtime::make_call((is_empty
                                         ? Runtime::EFACETYPE
                                         : Runtime::IFACETYPE),
-                                       loc, 1, ref);
+                                       loc, 1, this->expr_);
   Temporary_reference_expression* lhs =
     Expression::make_temporary_reference(descriptor_temp, loc);
   lhs->set_is_lvalue();
@@ -4384,7 +4373,9 @@
     const
 {
   ast_dump_context->print_indent();
-  ast_dump_context->ostream() << "switch " << this->var_->name() << " = ";
+  ast_dump_context->ostream() << "switch ";
+  if (!this->name_.empty())
+    ast_dump_context->ostream() << this->name_ << " = ";
   ast_dump_context->dump_expression(this->expr_);
   ast_dump_context->ostream() << " .(type)";
   if (ast_dump_context->dump_subblocks())
@@ -4399,10 +4390,10 @@
 // Make a type switch statement.
 
 Type_switch_statement*
-Statement::make_type_switch_statement(Named_object* var, Expression* expr,
+Statement::make_type_switch_statement(const std::string& name, Expression* 
expr,
                                      Location location)
 {
-  return new Type_switch_statement(var, expr, location);
+  return new Type_switch_statement(name, expr, location);
 }
 
 // Class Send_statement.
diff -r d42a0819e2eb go/statements.h
--- a/go/statements.h   Fri Feb 06 08:17:54 2015 -0800
+++ b/go/statements.h   Thu Mar 05 16:21:29 2015 -0800
@@ -250,7 +250,7 @@
 
   // Make a type switch statement.
   static Type_switch_statement*
-  make_type_switch_statement(Named_object* var, Expression*, Location);
+  make_type_switch_statement(const std::string&, Expression*, Location);
 
   // Make a send statement.
   static Send_statement*
@@ -1607,11 +1607,11 @@
 class Type_switch_statement : public Statement
 {
  public:
-  Type_switch_statement(Named_object* var, Expression* expr,
+  Type_switch_statement(const std::string& name, Expression* expr,
                        Location location)
     : Statement(STATEMENT_TYPE_SWITCH, location),
-      var_(var), expr_(expr), clauses_(NULL), break_label_(NULL)
-  { go_assert(var == NULL || expr == NULL); }
+      name_(name), expr_(expr), clauses_(NULL), break_label_(NULL)
+  { }
 
   // Add the clauses.
   void
@@ -1643,8 +1643,9 @@
   do_may_fall_through() const;
 
  private:
-  // The variable holding the value we are switching on.
-  Named_object* var_;
+  // The name of the variable declared in the type switch guard.  Empty if 
there
+  // is no variable declared.
+  std::string name_;
   // The expression we are switching on if there is no variable.
   Expression* expr_;
   // The type case clauses.

Reply via email to