compiler: avoid call duplication during order eval.
authorIan Lance Taylor <ian@gcc.gnu.org>
Tue, 27 Sep 2016 21:25:42 +0000 (21:25 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 27 Sep 2016 21:25:42 +0000 (21:25 +0000)
    During the compiler's order_evaluations() pass, duplicate
    call statements were being created and inserted into block
    statement lists in situations where there were calls returning
    multiple arguments. These duplicates were benign in that they
    were ignored during backend code generation, however they
    did cause duplicate calls in AST dumps. Tweak the order
    evaluation code to handle this case better and avoid inserting
    these duplicates.

    Fixes golang/go#17237

    Reviewed-on: https://go-review.googlesource.com/29857

From-SVN: r240559

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/gogo.cc

index e80ed9f94df2e329865ca9648fcd14baa998030a..1b53f8c10655da2dd6ecfe4ec594154409ff085c 100644 (file)
@@ -1,4 +1,4 @@
-1d8d834b5eb9f683cc06529145b353bb5b08e7ea
+8aca265d317059ae6d9721a4a231895d80d0a82c
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 7617815c98bbc11b7dcdccf8d85948d34a6ca86d..587ebd434a9057fe5e39f4dd39eb22d3c6d97f6b 100644 (file)
@@ -3616,11 +3616,21 @@ Order_eval::statement(Block* block, size_t* pindex, Statement* s)
          // be handled specially.  We can't create a temporary
          // because there is no type to give it.  Any actual uses of
          // the values will be done via Call_result_expressions.
-         s = Statement::make_statement(*pexpr, true);
-       }
+          //
+          // Since a given call expression can be shared by multiple
+          // Call_result_expressions, avoid hoisting the call the
+          // second time we see it here.
+          if (this->remember_expression(*pexpr))
+            s = NULL;
+          else
+            s = Statement::make_statement(*pexpr, true);
+        }
 
-      block->insert_statement_before(*pindex, s);
-      ++*pindex;
+      if (s != NULL)
+        {
+          block->insert_statement_before(*pindex, s);
+          ++*pindex;
+        }
     }
 
   if (init != orig_init)
@@ -7949,13 +7959,14 @@ Traverse::remember_type(const Type* type)
 }
 
 // Record that we are looking at an expression, and return true if we
-// have already seen it.
+// have already seen it. NB: this routine used to assert if the traverse
+// mask did not include expressions/types -- this is no longer the case,
+// since it can be useful to remember specific expressions during
+// walks that only cover statements.
 
 bool
 Traverse::remember_expression(const Expression* expression)
 {
-  go_assert((this->traverse_mask() & traverse_types) != 0
-            || (this->traverse_mask() & traverse_expressions) != 0);
   if (this->expressions_seen_ == NULL)
     this->expressions_seen_ = new Expressions_seen();
   std::pair<Expressions_seen::iterator, bool> ins =