Blame SOURCES/gcc32-c++-unitialized-self-ref.patch

6f1b0c
2004-12-02  Alexandre Oliva  <aoliva@redhat.com>
6f1b0c
6f1b0c
	* decl.c (copy_tree_replacing_r, struct replace_node): New.
6f1b0c
	(grok_reference_init): Use them to replace uses of a reference
6f1b0c
	being initialized with a NULL dereference.
6f1b0c
6f1b0c
2005-01-03  Jakub Jelinek  <jakub@redhat.com>
6f1b0c
6f1b0c
	* g++.dg/other/ref1.C: New test.
6f1b0c
6f1b0c
--- gcc/cp/decl.c.jj	2003-03-28 22:03:02.000000000 +0100
6f1b0c
+++ gcc/cp/decl.c	2005-01-03 11:45:24.669972609 +0100
6f1b0c
@@ -1,6 +1,6 @@
6f1b0c
 /* Process declarations and variables for C compiler.
6f1b0c
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
6f1b0c
-   2001, 2002, 2003  Free Software Foundation, Inc.
6f1b0c
+   2001, 2002, 2003, 2004  Free Software Foundation, Inc.
6f1b0c
    Contributed by Michael Tiemann (tiemann@cygnus.com)
6f1b0c
 
6f1b0c
 This file is part of GNU CC.
6f1b0c
@@ -7535,6 +7535,30 @@ start_decl_1 (decl)
6f1b0c
     DECL_INITIAL (decl) = NULL_TREE;
6f1b0c
 }
6f1b0c
 
6f1b0c
+static tree copy_tree_replacing_r PARAMS ((tree *, int *, void *));
6f1b0c
+
6f1b0c
+struct replace_node
6f1b0c
+{
6f1b0c
+  tree from, to;
6f1b0c
+};
6f1b0c
+
6f1b0c
+static tree
6f1b0c
+copy_tree_replacing_r (tp, walk_subtrees, data)
6f1b0c
+     tree *tp;
6f1b0c
+     int *walk_subtrees;
6f1b0c
+     void *data;
6f1b0c
+{
6f1b0c
+  struct replace_node *rn = data;
6f1b0c
+
6f1b0c
+  if (*tp != rn->from)
6f1b0c
+    return copy_tree_r (tp, walk_subtrees, NULL);
6f1b0c
+
6f1b0c
+  *tp = rn->to;
6f1b0c
+  *walk_subtrees = 0;
6f1b0c
+
6f1b0c
+  return NULL;
6f1b0c
+}
6f1b0c
+
6f1b0c
 /* Handle initialization of references.
6f1b0c
    These three arguments are from `cp_finish_decl', and have the
6f1b0c
    same meaning here that they do there.
6f1b0c
@@ -7565,6 +7589,35 @@ grok_reference_init (decl, type, init)
6f1b0c
       return NULL_TREE;
6f1b0c
     }
6f1b0c
 
6f1b0c
+  /* Replace occurrences of a reference variable in its own
6f1b0c
+     initializer with a zero-initialized NULL reference.  If we don't
6f1b0c
+     do this and the reference initializer ends up requiring a
6f1b0c
+     temporary (as it almost always will in this case), we'll end up
6f1b0c
+     with the initializer of the temporary referencing the reference
6f1b0c
+     variable before it's in scope, which crashes because we haven't
6f1b0c
+     expanded the reference declaration yet, so its DECL_RTL is NULL.
6f1b0c
+     This is equivalent to zero-initializing the reference variable,
6f1b0c
+     expanding the temporary definition with initializer, then binding
6f1b0c
+     the reference to the temporary, without requiring all the revamp
6f1b0c
+     in reference handling that mainline undergone for GCC 3.4.  It
6f1b0c
+     actually changes behavior a little bit, in that a reference
6f1b0c
+     initialized to itself will now be bound to a NULL reference
6f1b0c
+     instead of getting an indeterminate value, but since using it
6f1b0c
+     before initialization invokes undefined behavior, either way is
6f1b0c
+     fine.  */
6f1b0c
+  if (find_tree (init, decl))
6f1b0c
+    {
6f1b0c
+      struct replace_node rn;
6f1b0c
+
6f1b0c
+      rn.from = decl;
6f1b0c
+      rn.to = build1 (NOP_EXPR, type, integer_zero_node);
6f1b0c
+      
6f1b0c
+      walk_tree (&init, copy_tree_replacing_r, &rn, NULL);
6f1b0c
+
6f1b0c
+      if (warn_uninitialized)
6f1b0c
+	warning ("reference used in its own initializer");
6f1b0c
+    }
6f1b0c
+
6f1b0c
   if (TREE_CODE (init) == TREE_LIST)
6f1b0c
     init = build_compound_expr (init);
6f1b0c
 
6f1b0c
--- gcc/testsuite/g++.dg/other/ref1.C.jj	2005-01-03 11:46:43.005868429 +0100
6f1b0c
+++ gcc/testsuite/g++.dg/other/ref1.C	2005-01-03 11:47:34.475601869 +0100
6f1b0c
@@ -0,0 +1,19 @@
6f1b0c
+// { dg-do compile }
6f1b0c
+// { dg-options "-O2" }
6f1b0c
+
6f1b0c
+struct A
6f1b0c
+{
6f1b0c
+  A ();
6f1b0c
+  ~A ();
6f1b0c
+};
6f1b0c
+
6f1b0c
+extern const A &bar ();
6f1b0c
+extern A baz ();
6f1b0c
+extern int operator!= (const A &x, const A &y);
6f1b0c
+
6f1b0c
+void foo (const A &x)
6f1b0c
+{
6f1b0c
+  /* This has undefined behaviour, as a is used before it is initialized.
6f1b0c
+     Still, we shouldn't ICE on it.  */
6f1b0c
+  const A &a = a != bar () ? x : baz ();
6f1b0c
+}