public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
From: Ian Lance Taylor <ian@gcc.gnu.org>
To: gcc-cvs@gcc.gnu.org
Subject: [gcc r12-5181] compiler: traverse func subexprs when creating func descriptors
Date: Thu, 11 Nov 2021 20:22:20 +0000 (GMT)	[thread overview]
Message-ID: <20211111202220.DBC913857C7F@sourceware.org> (raw)

https://gcc.gnu.org/g:7846156274db4c58317871c7d5e049e6f2b0ca10

commit r12-5181-g7846156274db4c58317871c7d5e049e6f2b0ca10
Author: Ian Lance Taylor <iant@golang.org>
Date:   Wed Nov 10 18:15:12 2021 -0800

    compiler: traverse func subexprs when creating func descriptors
    
    Fix the Create_func_descriptors pass to traverse the subexpressions of
    the function in a Call_expression.  There are no subexpressions in the
    normal case of calling a function a method directly, but there are
    subexpressions when in code like F().M() when F returns an interface type.
    
    Forgetting to traverse the function subexpressions was almost entirely
    hidden by the fact that we also created the necessary thunks in
    Bound_method_expression::do_flatten and
    Interface_field_reference_expression::do_get_backend.  However, when
    the thunks were created there, they did not go through the
    order_evaluations pass.  This almost always worked, but failed in the
    case in which the function being thunked returned multiple results, as
    order_evaluations takes the necessary step of moving the
    Call_expression into its own statement, and that would not happen when
    order_evaluations was not called.  Avoid hiding errors like this by
    changing those methods to only lookup the previously created thunk,
    rather than creating it if it was not already created.
    
    The test case for this is https://golang.org/cl/363156.
    
    Fixes https://golang.org/issue/49512
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/363274

Diff:
---
 gcc/go/gofrontend/MERGE          |  2 +-
 gcc/go/gofrontend/expressions.cc | 57 +++++++++++++++++++++++++++++++++-------
 gcc/go/gofrontend/expressions.h  |  8 ++++++
 gcc/go/gofrontend/gogo.cc        |  5 ++++
 4 files changed, 61 insertions(+), 11 deletions(-)

diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index e7ff6705563..05e47ec3fa9 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-128ea3dce9b8753167f33d0a96bd093a6cbd58b8
+3e9f4ee16683883ccfb8661d99318c74bb7a4bef
 
 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.cc b/gcc/go/gofrontend/expressions.cc
index ddb1d91f3e5..79702821336 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -7981,7 +7981,7 @@ Bound_method_expression::do_check_types(Gogo*)
 Bound_method_expression::Method_value_thunks
   Bound_method_expression::method_value_thunks;
 
-// Find or create the thunk for METHOD.
+// Find or create the thunk for FN.
 
 Named_object*
 Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
@@ -8078,14 +8078,28 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
   gogo->add_statement(s);
   Block* b = gogo->finish_block(loc);
   gogo->add_block(b, loc);
+
+  // This is called after lowering but before determine_types.
   gogo->lower_block(new_no, b);
-  gogo->flatten_block(new_no, b);
+
   gogo->finish_function(loc);
 
   ins.first->second = new_no;
   return new_no;
 }
 
+// Look up a thunk for FN.
+
+Named_object*
+Bound_method_expression::lookup_thunk(Named_object* fn)
+{
+  Method_value_thunks::const_iterator p =
+    Bound_method_expression::method_value_thunks.find(fn);
+  if (p == Bound_method_expression::method_value_thunks.end())
+    return NULL;
+  return p->second;
+}
+
 // Return an expression to check *REF for nil while dereferencing
 // according to FIELD_INDEXES.  Update *REF to build up the field
 // reference.  This is a static function so that we don't have to
@@ -8129,10 +8143,11 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*,
 {
   Location loc = this->location();
 
-  Named_object* thunk = Bound_method_expression::create_thunk(gogo,
-							      this->method_,
-							      this->function_);
-  if (thunk->is_erroneous())
+  Named_object* thunk = Bound_method_expression::lookup_thunk(this->function_);
+
+  // The thunk should have been created during the
+  // create_function_descriptors pass.
+  if (thunk == NULL || thunk->is_erroneous())
     {
       go_assert(saw_errors());
       return Expression::make_error(loc);
@@ -14757,14 +14772,34 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo,
   gogo->add_statement(s);
   Block* b = gogo->finish_block(loc);
   gogo->add_block(b, loc);
+
+  // This is called after lowering but before determine_types.
   gogo->lower_block(new_no, b);
-  gogo->flatten_block(new_no, b);
+
   gogo->finish_function(loc);
 
   ins.first->second->push_back(std::make_pair(name, new_no));
   return new_no;
 }
 
+// Lookup a thunk to call method NAME on TYPE.
+
+Named_object*
+Interface_field_reference_expression::lookup_thunk(Interface_type* type,
+						   const std::string& name)
+{
+  Interface_method_thunks::const_iterator p =
+    Interface_field_reference_expression::interface_method_thunks.find(type);
+  if (p == Interface_field_reference_expression::interface_method_thunks.end())
+    return NULL;
+  for (Method_thunks::const_iterator pm = p->second->begin();
+       pm != p->second->end();
+       ++pm)
+    if (pm->first == name)
+      return pm->second;
+  return NULL;
+}
+
 // Get the backend representation for a method value.
 
 Bexpression*
@@ -14778,9 +14813,11 @@ Interface_field_reference_expression::do_get_backend(Translate_context* context)
     }
 
   Named_object* thunk =
-    Interface_field_reference_expression::create_thunk(context->gogo(),
-						       type, this->name_);
-  if (thunk->is_erroneous())
+    Interface_field_reference_expression::lookup_thunk(type, this->name_);
+
+  // The thunk should have been created during the
+  // create_function_descriptors pass.
+  if (thunk == NULL || thunk->is_erroneous())
     {
       go_assert(saw_errors());
       return context->backend()->error_expression();
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 93483544e46..92e8d8d96b4 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -3405,6 +3405,10 @@ class Bound_method_expression : public Expression
   static Named_object*
   create_thunk(Gogo*, const Method* method, Named_object* function);
 
+  // Look up a thunk.
+  static Named_object*
+  lookup_thunk(Named_object* function);
+
  protected:
   int
   do_traverse(Traverse*);
@@ -3578,6 +3582,10 @@ class Interface_field_reference_expression : public Expression
   static Named_object*
   create_thunk(Gogo*, Interface_type* type, const std::string& name);
 
+  // Look up a thunk.
+  static Named_object*
+  lookup_thunk(Interface_type* type, const std::string& name);
+
   // Return an expression for the pointer to the function to call.
   Expression*
   get_function();
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 95b76bd317c..290d294e83b 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -3430,6 +3430,11 @@ Create_function_descriptors::expression(Expression** pexpr)
 	      if (args->traverse(this) == TRAVERSE_EXIT)
 		return TRAVERSE_EXIT;
 	    }
+
+	  // Traverse the subexpressions of the function, if any.
+	  if (fn->traverse_subexpressions(this) == TRAVERSE_EXIT)
+	    return TRAVERSE_EXIT;
+
 	  return TRAVERSE_SKIP_COMPONENTS;
 	}
     }


                 reply	other threads:[~2021-11-11 20:22 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211111202220.DBC913857C7F@sourceware.org \
    --to=ian@gcc.gnu.org \
    --cc=gcc-cvs@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).