From a8b9ee6feb54764859c6f113983255a6dec897d6 Mon Sep 17 00:00:00 2001
From: Ian Lance Taylor <ian@gcc.gnu.org>
Date: Thu, 11 Jul 2019 21:37:33 +0000
Subject: [PATCH] compiler: ensure evaluation order in type hash/eq functions

    The type hash and equality functions are generated after the
    order_evaluations pass. They may contain shortcut operators and
    Set_and_use_temporary_expressions (e.g. from lowering a
    Binary_exprssion) that need to be ordered. Run order_evaluations
    and remove_shortcuts on these functions. (The hash functions
    may be fine, but to be on the safe side we run on them anyway.
    We do need to run on the equality functions.)

    A Set_and_use_temporary_expression is effectively an assignment,
    so it needs to be ordered. Otherwise if we insert a temporary
    statement before it, we may get wrong evaluation order.

    A test case is CL 185818.

    Fixes golang/go#33062.

    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/185817

From-SVN: r273425
---
 gcc/go/gofrontend/MERGE         |  2 +-
 gcc/go/gofrontend/expressions.h |  4 ++++
 gcc/go/gofrontend/gogo.cc       | 18 ++++++++++++++++++
 gcc/go/gofrontend/gogo.h        |  8 ++++++++
 gcc/go/gofrontend/types.cc      |  4 ++++
 5 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 7b3f874123da..28fc22309dd9 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-ec754ff4617d564d3dc377121ea9ac5e55f6535a
+70ceba5e95716653b9f829a457a44a829175d4da
 
 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 2c6a08094d10..3b65e7a5f0c9 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -1627,6 +1627,10 @@ class Set_and_use_temporary_expression : public Expression
 				      this->location());
   }
 
+  bool
+  do_must_eval_in_order() const
+  { return true; }
+
   bool
   do_is_addressable() const
   { return true; }
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 234a4f44a4bd..f9a18bc46277 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -4097,6 +4097,15 @@ Gogo::order_evaluations()
   this->traverse(&order_eval);
 }
 
+// Order evaluations in a block.
+
+void
+Gogo::order_block(Block* block)
+{
+  Order_eval order_eval(this);
+  block->traverse(&order_eval);
+}
+
 // A traversal class used to find a single shortcut operator within an
 // expression.
 
@@ -4306,6 +4315,15 @@ Gogo::remove_shortcuts()
   this->traverse(&shortcuts);
 }
 
+// Turn shortcut operators into explicit if statements in a block.
+
+void
+Gogo::remove_shortcuts_in_block(Block* block)
+{
+  Shortcuts shortcuts(this);
+  block->traverse(&shortcuts);
+}
+
 // Traversal to flatten parse tree after order of evaluation rules are applied.
 
 class Flatten : public Traverse
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index cb8e25f446f9..6ffdc59bebc5 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -749,10 +749,18 @@ class Gogo
   void
   remove_shortcuts();
 
+  // Turn short-cut operators into explicit if statements in a block.
+  void
+  remove_shortcuts_in_block(Block*);
+
   // Use temporary variables to force order of evaluation.
   void
   order_evaluations();
 
+  // Order evaluations in a block.
+  void
+  order_block(Block*);
+
   // Add write barriers as needed.
   void
   add_write_barriers();
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index cc65bd8d749e..b46525d78727 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -2098,6 +2098,8 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, int64_t size,
   Block* b = gogo->finish_block(bloc);
   gogo->add_block(b, bloc);
   gogo->lower_block(hash_fn, b);
+  gogo->order_block(b);
+  gogo->remove_shortcuts_in_block(b);
   gogo->finish_function(bloc);
 
   Named_object *equal_fn = gogo->start_function(equal_name, equal_fntype,
@@ -2119,6 +2121,8 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, int64_t size,
   b = gogo->finish_block(bloc);
   gogo->add_block(b, bloc);
   gogo->lower_block(equal_fn, b);
+  gogo->order_block(b);
+  gogo->remove_shortcuts_in_block(b);
   gogo->finish_function(bloc);
 
   // Build the function descriptors for the type descriptor to refer to.
-- 
GitLab