The problem here was that break_out_target_exprs was duplicating a SAVE_EXPR, so we ended up evaluating the inner call twice. Fixed by mapping them as well as TARGET_EXPRs.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit 7dcc38201366f5c3043e78f7074ba863229b21d3
Author: Jason Merrill <ja...@redhat.com>
Date:   Mon Jun 15 15:25:10 2015 -0400

    	PR c++/58063
    	* tree.c (bot_manip): Remap SAVE_EXPR.

diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 3553d7c..a52e6f4 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2423,6 +2423,29 @@ bot_manip (tree* tp, int* walk_subtrees, void* data)
       *walk_subtrees = 0;
       return NULL_TREE;
     }
+  if (TREE_CODE (*tp) == SAVE_EXPR)
+    {
+      t = *tp;
+      splay_tree_node n = splay_tree_lookup (target_remap,
+					     (splay_tree_key) t);
+      if (n)
+	{
+	  *tp = (tree)n->value;
+	  *walk_subtrees = 0;
+	}
+      else
+	{
+	  copy_tree_r (tp, walk_subtrees, NULL);
+	  splay_tree_insert (target_remap,
+			     (splay_tree_key)t,
+			     (splay_tree_value)*tp);
+	  /* Make sure we don't remap an already-remapped SAVE_EXPR.  */
+	  splay_tree_insert (target_remap,
+			     (splay_tree_key)*tp,
+			     (splay_tree_value)*tp);
+	}
+      return NULL_TREE;
+    }
 
   /* Make a copy of this node.  */
   t = copy_tree_r (tp, walk_subtrees, NULL);
diff --git a/gcc/testsuite/g++.dg/overload/defarg10.C b/gcc/testsuite/g++.dg/overload/defarg10.C
new file mode 100644
index 0000000..b8275d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/defarg10.C
@@ -0,0 +1,28 @@
+// PR c++/58063
+// { dg-do run }
+
+struct basic_ios
+{
+  bool operator!() const { return false; }
+};
+
+struct ostream : virtual basic_ios
+{
+};
+
+int i;
+
+ostream& operator<<(ostream& os, const char* s) {
+  ++i;
+  return os;
+}
+
+ostream cout;
+
+void f(bool x = !(cout << "hi!\n")) { }
+
+int main() {
+  f();
+  if (i != 1)
+    __builtin_abort();
+}

Reply via email to