This Go frontend patch by Cherry Zhang ensures correct evaluation order in type hash/equality 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 https://golang.org/cl/185818. This fixes https://golang.org/issue/33062. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 273364) +++ gcc/go/gofrontend/MERGE (working copy) @@ -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. Index: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 273307) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -1628,6 +1628,10 @@ class Set_and_use_temporary_expression : } bool + do_must_eval_in_order() const + { return true; } + + bool do_is_addressable() const { return true; } Index: gcc/go/gofrontend/gogo.cc =================================================================== --- gcc/go/gofrontend/gogo.cc (revision 273364) +++ gcc/go/gofrontend/gogo.cc (working copy) @@ -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 Index: gcc/go/gofrontend/gogo.h =================================================================== --- gcc/go/gofrontend/gogo.h (revision 273364) +++ gcc/go/gofrontend/gogo.h (working copy) @@ -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(); Index: gcc/go/gofrontend/types.cc =================================================================== --- gcc/go/gofrontend/types.cc (revision 273307) +++ gcc/go/gofrontend/types.cc (working copy) @@ -2098,6 +2098,8 @@ Type::write_specific_type_functions(Gogo 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 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.