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