For some future work on the Go frontend it will be annoying to have to
make Expression::type work before the lowering pass, so this patch
changes the frontend so that that doesn't happen.  Bootstrapped and
ran Go testsuite on x86_64-pc-linux-gnu.  Committed to mainline.

Ian

patch.txt
19b5a1147764bc867f2743fafa2f05da239618d6
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index edfbe46d8f4..7eea97765c3 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-e3bfc0889237a5bb8aa7ae30e1cff14f90a5f941
+bbc1effb1a8a757a38011074f1d4477fae3936f5
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 9f8f4e9255b..93483544e46 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -999,7 +999,9 @@ class Expression
   determine_type_no_context();
 
   // Return the current type of the expression.  This may be changed
-  // by determine_type.
+  // by determine_type.  This should not be called before the lowering
+  // pass, unless the is_type_expression method returns true (i.e.,
+  // this is an EXPRESSION_TYPE).
   Type*
   type()
   { return this->do_type(); }
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index cd692506efc..c6ce6230c58 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -11789,8 +11789,9 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, 
const Methods* methods,
        {
          stub = gogo->start_function(stub_name, stub_type, false,
                                      fntype->location());
-         Type::build_one_stub_method(gogo, m, buf, stub_params,
-                                     fntype->is_varargs(), location);
+         Type::build_one_stub_method(gogo, m, buf, receiver_type, stub_params,
+                                     fntype->is_varargs(), stub_results,
+                                     location);
          gogo->finish_function(fntype->location());
 
          if (type->named_type() == NULL && stub->is_function())
@@ -11810,16 +11811,20 @@ Type::build_stub_methods(Gogo* gogo, const Type* 
type, const Methods* methods,
 void
 Type::build_one_stub_method(Gogo* gogo, Method* method,
                            const char* receiver_name,
+                           const Type* receiver_type,
                            const Typed_identifier_list* params,
                            bool is_varargs,
+                           const Typed_identifier_list* results,
                            Location location)
 {
   Named_object* receiver_object = gogo->lookup(receiver_name, NULL);
   go_assert(receiver_object != NULL);
 
   Expression* expr = Expression::make_var_reference(receiver_object, location);
-  expr = Type::apply_field_indexes(expr, method->field_indexes(), location);
-  if (expr->type()->points_to() == NULL)
+  const Type* expr_type = receiver_type;
+  expr = Type::apply_field_indexes(expr, method->field_indexes(), location,
+                                  &expr_type);
+  if (expr_type->points_to() == NULL)
     expr = Expression::make_unary(OPERATOR_AND, expr, location);
 
   Expression_list* arguments;
@@ -11844,8 +11849,7 @@ Type::build_one_stub_method(Gogo* gogo, Method* method,
   go_assert(func != NULL);
   Call_expression* call = Expression::make_call(func, arguments, is_varargs,
                                                location);
-
-  gogo->add_statement(Statement::make_return_from_call(call, location));
+  Type::add_return_from_results(gogo, call, results, location);
 }
 
 // Build direct interface stub methods for TYPE as needed.  METHODS
@@ -11954,8 +11958,9 @@ Type::build_direct_iface_stub_methods(Gogo* gogo, const 
Type* type,
         {
           stub = gogo->start_function(stub_name, stub_type, false,
                                       fntype->location());
-          Type::build_one_iface_stub_method(gogo, m, buf, stub_params,
-                                            fntype->is_varargs(), loc);
+         Type::build_one_iface_stub_method(gogo, m, buf, stub_params,
+                                           fntype->is_varargs(), stub_results,
+                                           loc);
           gogo->finish_function(fntype->location());
 
           if (type->named_type() == NULL && stub->is_function())
@@ -11982,7 +11987,9 @@ void
 Type::build_one_iface_stub_method(Gogo* gogo, Method* method,
                                   const char* receiver_name,
                                   const Typed_identifier_list* params,
-                                  bool is_varargs, Location loc)
+                                 bool is_varargs,
+                                 const Typed_identifier_list* results,
+                                 Location loc)
 {
   Named_object* receiver_object = gogo->lookup(receiver_name, NULL);
   go_assert(receiver_object != NULL);
@@ -12014,31 +12021,63 @@ Type::build_one_iface_stub_method(Gogo* gogo, Method* 
method,
   go_assert(func != NULL);
   Call_expression* call = Expression::make_call(func, arguments, is_varargs,
                                                 loc);
+  Type::add_return_from_results(gogo, call, results, loc);
+}
 
-  gogo->add_statement(Statement::make_return_from_call(call, loc));
+// Build and add a return statement from a call expression and a list
+// of result parameters.  All we need to know is the number of
+// results.
+
+void
+Type::add_return_from_results(Gogo* gogo, Call_expression* call,
+                               const Typed_identifier_list* results,
+                               Location loc)
+{
+  Statement* s;
+  if (results == NULL || results->empty())
+    s = Statement::make_statement(call, true);
+  else
+    {
+      Expression_list* vals = new Expression_list();
+      size_t rc = results->size();
+      if (rc == 1)
+       vals->push_back(call);
+      else
+       {
+         for (size_t i = 0; i < rc; ++i)
+           vals->push_back(Expression::make_call_result(call, i));
+       }
+      s = Statement::make_return_statement(vals, loc);
+    }
+
+  gogo->add_statement(s);
 }
 
 // Apply FIELD_INDEXES to EXPR.  The field indexes have to be applied
-// in reverse order.
+// in reverse order.  *PEXPR_TYPE maintains the type of EXPR; we use
+// this to avoid calling EXPR->type() before the lowering pass.
 
 Expression*
 Type::apply_field_indexes(Expression* expr,
                          const Method::Field_indexes* field_indexes,
-                         Location location)
+                         Location location,
+                         const Type** pexpr_type)
 {
   if (field_indexes == NULL)
     return expr;
-  expr = Type::apply_field_indexes(expr, field_indexes->next, location);
-  Struct_type* stype = expr->type()->deref()->struct_type();
+  expr = Type::apply_field_indexes(expr, field_indexes->next, location,
+                                  pexpr_type);
+  const Type* expr_type = *pexpr_type;
+  const Struct_type* stype = expr_type->deref()->struct_type();
   go_assert(stype != NULL
             && field_indexes->field_index < stype->field_count());
-  if (expr->type()->struct_type() == NULL)
+  if (expr_type->struct_type() == NULL)
     {
-      go_assert(expr->type()->points_to() != NULL);
+      go_assert(expr_type->points_to()->struct_type() == stype);
       expr = Expression::make_dereference(expr, Expression::NIL_CHECK_DEFAULT,
                                           location);
-      go_assert(expr->type()->struct_type() == stype);
     }
+  *pexpr_type = stype->field(field_indexes->field_index)->type();
   return Expression::make_field_reference(expr, field_indexes->field_index,
                                          location);
 }
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index 0c5180668ea..a33453afc84 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -1355,8 +1355,9 @@ class Type
 
   static void
   build_one_stub_method(Gogo*, Method*, const char* receiver_name,
+                       const Type* receiver_type,
                        const Typed_identifier_list*, bool is_varargs,
-                       Location);
+                       const Typed_identifier_list*, Location);
 
   // Build direct interface stub methods for a type.
   static void
@@ -1364,12 +1365,16 @@ class Type
 
   static void
   build_one_iface_stub_method(Gogo*, Method*, const char*,
-                              const Typed_identifier_list*,
-                              bool, Location);
+                              const Typed_identifier_list*, bool,
+                             const Typed_identifier_list*, Location);
+
+  static void
+  add_return_from_results(Gogo*, Call_expression*,
+                         const Typed_identifier_list*, Location);
 
   static Expression*
   apply_field_indexes(Expression*, const Method::Field_indexes*,
-                     Location);
+                     Location, const Type**);
 
   // Look for a field or method named NAME in TYPE.
   static bool

Reply via email to