aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@codesourcery.com>2001-01-11 12:29:20 +0000
committerNathan Sidwell <nathan@gcc.gnu.org>2001-01-11 12:29:20 +0000
commit96a1e32dcdf973cab1c308cfcdfcf6f07444b2cc (patch)
treeec5b5da0d3a77d08ddf43c7b5c39291e71111bc5
parent34e225a30bcb010bc46846eb3ea6ad9e1321034d (diff)
downloadgcc-96a1e32dcdf973cab1c308cfcdfcf6f07444b2cc.zip
gcc-96a1e32dcdf973cab1c308cfcdfcf6f07444b2cc.tar.gz
gcc-96a1e32dcdf973cab1c308cfcdfcf6f07444b2cc.tar.bz2
call.c (convert_default_arg): Check for unprocessed DEFAULT_ARG.
cp: * call.c (convert_default_arg): Check for unprocessed DEFAULT_ARG. * cp-tree.h (replace_defarg): Move to spew.c. (maybe_snarf_defarg, add_defarg_fn, do_pending_defargs): Move to spew.c, which is where they really are. (done_pending_defargs): Declare. (unprocessed_defarg_fn): Declare. * decl.c (replace_defarg): Move to spew.c * parse.y (structsp): Call done_pending_defargs. * spew.c (defarg_fns): Rearrange list structure. (defarg_fnsdone): New static variable. (defarg_depfns): New static variable. (init_spew): Adjust. (add_defarg_fn): Store the type in TREE_TYPE. (do_pending_defargs): Detect and deal with ordering constraints and circularity. (done_pending_defargs): New function. (unprocessed_defarg_fn): New function. (replace_defarg): Moved from decl.c. Robustify. Don't save if circularity detected. testsuite: * g++.old-deja/g++.other/defarg7.C: New test. * g++.old-deja/g++.other/defarg8.C: New test. From-SVN: r38903
-rw-r--r--gcc/cp/ChangeLog23
-rw-r--r--gcc/cp/call.c20
-rw-r--r--gcc/cp/cp-tree.h10
-rw-r--r--gcc/cp/decl.c14
-rw-r--r--gcc/cp/parse.y1
-rw-r--r--gcc/cp/spew.c121
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/defarg7.C41
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/defarg8.C24
9 files changed, 237 insertions, 26 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index d72b8b0..0981c7e 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,28 @@
2001-01-11 Nathan Sidwell <nathan@codesourcery.com>
+ * call.c (convert_default_arg): Check for unprocessed
+ DEFAULT_ARG.
+ * cp-tree.h (replace_defarg): Move to spew.c.
+ (maybe_snarf_defarg, add_defarg_fn, do_pending_defargs): Move to
+ spew.c, which is where they really are.
+ (done_pending_defargs): Declare.
+ (unprocessed_defarg_fn): Declare.
+ * decl.c (replace_defarg): Move to spew.c
+ * parse.y (structsp): Call done_pending_defargs.
+ * spew.c (defarg_fns): Rearrange list structure.
+ (defarg_fnsdone): New static variable.
+ (defarg_depfns): New static variable.
+ (init_spew): Adjust.
+ (add_defarg_fn): Store the type in TREE_TYPE.
+ (do_pending_defargs): Detect and deal with ordering constraints
+ and circularity.
+ (done_pending_defargs): New function.
+ (unprocessed_defarg_fn): New function.
+ (replace_defarg): Moved from decl.c. Robustify. Don't save
+ if circularity detected.
+
+2001-01-11 Nathan Sidwell <nathan@codesourcery.com>
+
* pt.c (unify): Check array has a domain, before checking
whether it is variable sized.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index a855963..5f12f7e 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -3953,6 +3953,26 @@ convert_default_arg (type, arg, fn, parmnum)
tree fn;
int parmnum;
{
+ if (TREE_CODE (arg) == DEFAULT_ARG)
+ {
+ /* When processing the default args for a class, we can find that
+ there is an ordering constraint, and we call a function who's
+ default args have not yet been converted. For instance,
+ class A {
+ A (int = 0);
+ void Foo (A const & = A ());
+ };
+ We must process A::A before A::Foo's default arg can be converted.
+ Remember the dependent function, so do_pending_defargs can retry,
+ and check loops. */
+ unprocessed_defarg_fn (fn);
+
+ /* Don't return error_mark node, as we won't be able to distinguish
+ genuine errors from this case, and that would lead to repeated
+ diagnostics. Just make something of the right type. */
+ return build1 (NOP_EXPR, type, integer_zero_node);
+ }
+
if (fn && DECL_TEMPLATE_INFO (fn))
arg = tsubst_default_argument (fn, type, arg);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2c22954..eea27e0 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -3874,7 +3874,6 @@ extern tree finish_method PARAMS ((tree));
extern void hack_incomplete_structures PARAMS ((tree));
extern tree maybe_build_cleanup PARAMS ((tree));
extern void finish_stmt PARAMS ((void));
-extern void replace_defarg PARAMS ((tree, tree));
extern void print_other_binding_stack PARAMS ((struct binding_level *));
extern void revert_static_member_fn PARAMS ((tree));
extern void fixup_anonymous_aggr PARAMS ((tree));
@@ -4085,9 +4084,6 @@ extern void compiler_error PARAMS ((const char *, ...))
ATTRIBUTE_PRINTF_1;
extern void yyerror PARAMS ((const char *));
extern void clear_inline_text_obstack PARAMS ((void));
-extern void maybe_snarf_defarg PARAMS ((void));
-extern void add_defarg_fn PARAMS ((tree));
-extern void do_pending_defargs PARAMS ((void));
extern void yyhook PARAMS ((int));
extern int cp_type_qual_from_rid PARAMS ((tree));
@@ -4345,6 +4341,12 @@ extern int peekyylex PARAMS ((void));
extern int yylex PARAMS ((void));
extern tree arbitrate_lookup PARAMS ((tree, tree, tree));
extern tree frob_opname PARAMS ((tree));
+extern void maybe_snarf_defarg PARAMS ((void));
+extern void add_defarg_fn PARAMS ((tree));
+extern void do_pending_defargs PARAMS ((void));
+extern void done_pending_defargs PARAMS ((void));
+extern void unprocessed_defarg_fn PARAMS ((tree));
+extern void replace_defarg PARAMS ((tree, tree));
/* in tree.c */
extern void init_tree PARAMS ((void));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 66a285c6..ff3084e 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -11950,20 +11950,6 @@ grokparms (first_parm)
return result;
}
-/* Called from the parser to update an element of TYPE_ARG_TYPES for some
- FUNCTION_TYPE with the newly parsed version of its default argument, which
- was previously digested as text. See snarf_defarg et al in lex.c. */
-
-void
-replace_defarg (arg, init)
- tree arg, init;
-{
- if (! processing_template_decl
- && ! can_convert_arg (TREE_VALUE (arg), TREE_TYPE (init), init))
- cp_pedwarn ("invalid type `%T' for default argument to `%T'",
- TREE_TYPE (init), TREE_VALUE (arg));
- TREE_PURPOSE (arg) = init;
-}
/* D is a constructor or overloaded `operator='. Returns non-zero if
D's arguments allow it to be a copy constructor, or copy assignment
diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y
index f74fae4..dca0992 100644
--- a/gcc/cp/parse.y
+++ b/gcc/cp/parse.y
@@ -2271,6 +2271,7 @@ structsp:
}
pending_defargs
{
+ done_pending_defargs ();
begin_inline_definitions ();
}
pending_inlines
diff --git a/gcc/cp/spew.c b/gcc/cp/spew.c
index 3fc1469..d7fd78e 100644
--- a/gcc/cp/spew.c
+++ b/gcc/cp/spew.c
@@ -164,10 +164,14 @@ char *inline_text_firstobj;
through and parse all of them using do_pending_defargs. Since yacc
parsers are not reentrant, we retain defargs state in these two
variables so that subsequent calls to do_pending_defargs can resume
- where the previous call left off. */
+ where the previous call left off. DEFARG_FNS is a tree_list where
+ the TREE_TYPE is the current_class_type, TREE_VALUE is the FUNCTION_DECL,
+ and TREE_PURPOSE is the list unprocessed dependent functions. */
-static tree defarg_fns;
-static tree defarg_parm;
+static tree defarg_fns; /* list of functions with unprocessed defargs */
+static tree defarg_parm; /* current default parameter */
+static tree defarg_depfns; /* list of unprocessed fns met during current fn. */
+static tree defarg_fnsdone; /* list of fns with circular defargs */
/* Initialize obstacks. Called once, from init_parse. */
@@ -180,6 +184,8 @@ init_spew ()
gcc_obstack_init (&feed_obstack);
ggc_add_tree_root (&defarg_fns, 1);
ggc_add_tree_root (&defarg_parm, 1);
+ ggc_add_tree_root (&defarg_depfns, 1);
+ ggc_add_tree_root (&defarg_fnsdone, 1);
ggc_add_root (&pending_inlines, 1, sizeof (struct unparsed_text *),
mark_pending_inlines);
@@ -1267,7 +1273,10 @@ add_defarg_fn (decl)
if (TREE_CODE (decl) == FUNCTION_DECL)
TREE_VALUE (defarg_fns) = decl;
else
- defarg_fns = tree_cons (current_class_type, decl, defarg_fns);
+ {
+ defarg_fns = tree_cons (NULL_TREE, decl, defarg_fns);
+ TREE_TYPE (defarg_fns) = current_class_type;
+ }
}
/* Helper for do_pending_defargs. Starts the parsing of a default arg. */
@@ -1305,12 +1314,14 @@ do_pending_defargs ()
if (defarg_parm)
finish_defarg ();
- for (; defarg_fns; defarg_fns = TREE_CHAIN (defarg_fns))
+ for (; defarg_fns;)
{
+ tree current = defarg_fns;
+
tree defarg_fn = TREE_VALUE (defarg_fns);
if (defarg_parm == NULL_TREE)
{
- push_nested_class (TREE_PURPOSE (defarg_fns), 1);
+ push_nested_class (TREE_TYPE (defarg_fns), 1);
pushlevel (0);
if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
maybe_begin_member_template_processing (defarg_fn);
@@ -1324,8 +1335,12 @@ do_pending_defargs ()
defarg_parm = TREE_CHAIN (defarg_parm);
for (; defarg_parm; defarg_parm = TREE_CHAIN (defarg_parm))
- if (TREE_PURPOSE (defarg_parm)
- && TREE_CODE (TREE_PURPOSE (defarg_parm)) == DEFAULT_ARG)
+ if (!TREE_PURPOSE (defarg_parm)
+ || TREE_CODE (TREE_PURPOSE (defarg_parm)) != DEFAULT_ARG)
+ ;/* OK */
+ else if (TREE_PURPOSE (current) == error_mark_node)
+ DEFARG_POINTER (TREE_PURPOSE (defarg_parm)) = NULL;
+ else
{
feed_defarg (defarg_parm);
@@ -1342,6 +1357,96 @@ do_pending_defargs ()
poplevel (0, 0, 0);
pop_nested_class ();
+
+ defarg_fns = TREE_CHAIN (defarg_fns);
+ if (defarg_depfns)
+ {
+ /* This function's default args depend on unprocessed default args
+ of defarg_fns. We will need to reprocess this function, and
+ check for circular dependancies. */
+ tree a, b;
+
+ for (a = defarg_depfns, b = TREE_PURPOSE (current); a && b;
+ a = TREE_CHAIN (a), b = TREE_CHAIN (b))
+ if (TREE_VALUE (a) != TREE_VALUE (b))
+ goto different;
+ if (a || b)
+ {
+ different:;
+ TREE_CHAIN (current) = NULL_TREE;
+ defarg_fns = chainon (defarg_fns, current);
+ TREE_PURPOSE (current) = defarg_depfns;
+ }
+ else
+ {
+ cp_warning_at ("circular dependency in default args of `%#D'", defarg_fn);
+ /* No need to say what else is dependent, as they will be
+ picked up in another pass. */
+
+ /* Immediately repeat, but marked so that we break the loop. */
+ defarg_fns = current;
+ TREE_PURPOSE (current) = error_mark_node;
+ }
+ defarg_depfns = NULL_TREE;
+ }
+ else if (TREE_PURPOSE (current) == error_mark_node)
+ defarg_fnsdone = tree_cons (NULL_TREE, defarg_fn, defarg_fnsdone);
+ }
+}
+
+/* After parsing all the default arguments, we must clear any that remain,
+ which will be part of a circular dependency. */
+void
+done_pending_defargs ()
+{
+ for (; defarg_fnsdone; defarg_fnsdone = TREE_CHAIN (defarg_fnsdone))
+ {
+ tree fn = TREE_VALUE (defarg_fnsdone);
+ tree parms;
+
+ if (TREE_CODE (fn) == FUNCTION_DECL)
+ parms = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ else
+ parms = TYPE_ARG_TYPES (fn);
+ for (; parms; parms = TREE_CHAIN (parms))
+ if (TREE_PURPOSE (parms)
+ && TREE_CODE (TREE_PURPOSE (parms)) == DEFAULT_ARG)
+ {
+ my_friendly_assert (!DEFARG_POINTER (TREE_PURPOSE (parms)), 20010107);
+ TREE_PURPOSE (parms) = NULL_TREE;
+ }
+ }
+}
+
+/* In processing the current default arg, we called FN, but that call
+ required a default argument of FN, and that had not yet been processed.
+ Remember FN. */
+
+void
+unprocessed_defarg_fn (fn)
+ tree fn;
+{
+ defarg_depfns = tree_cons (NULL_TREE, fn, defarg_depfns);
+}
+
+/* Called from the parser to update an element of TYPE_ARG_TYPES for some
+ FUNCTION_TYPE with the newly parsed version of its default argument, which
+ was previously digested as text. */
+
+void
+replace_defarg (arg, init)
+ tree arg, init;
+{
+ if (init == error_mark_node)
+ TREE_PURPOSE (arg) = error_mark_node;
+ else
+ {
+ if (! processing_template_decl
+ && ! can_convert_arg (TREE_VALUE (arg), TREE_TYPE (init), init))
+ cp_pedwarn ("invalid type `%T' for default argument to `%T'",
+ TREE_TYPE (init), TREE_VALUE (arg));
+ if (!defarg_depfns)
+ TREE_PURPOSE (arg) = init;
}
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index a87cf88..4e44d8e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,14 @@
2001-01-11 Nathan Sidwell <nathan@codesourcery.com>
+ * g++.old-deja/g++.other/defarg7.C: New test.
+ * g++.old-deja/g++.other/defarg8.C: New test.
+
+2001-01-11 Nathan Sidwell <nathan@codesourcery.com>
+
+ * g++.old-deja/g++.pt/crash64.C: New test.
+
+2001-01-11 Nathan Sidwell <nathan@codesourcery.com>
+
* g++.old-deja/g++.pt/crash63.C: New test.
2001-01-11 Neil Booth <neil@daikokuya.demon.co.uk>
diff --git a/gcc/testsuite/g++.old-deja/g++.other/defarg7.C b/gcc/testsuite/g++.old-deja/g++.other/defarg7.C
new file mode 100644
index 0000000..cb5a6da
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.other/defarg7.C
@@ -0,0 +1,41 @@
+// Build don't link:
+
+// Copyright (C) 2000 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 7 Jan 2001 <nathan@codesourcery.com>
+
+// Bug 1038. Default args on class members can produce circular dependencies.
+// Make sure we spot them, and don't depend on a particular ordering.
+
+struct A
+{
+ static int Foo (int = Baz ()); // WARNING - circular
+ static int Baz (int = Foo ()); // WARNING - circular
+};
+
+struct Test
+{
+ Test (void * = 0);
+ void set (const Test &arg = Test ());
+};
+
+struct B
+{
+ static int Bar (int = Foo (1));
+ static int Foo (int = Baz ());
+ static int Baz (int = Foo (1));
+};
+
+int main ()
+{
+ Test t;
+ t.set ();
+ t.set (t);
+ B::Bar ();
+ B::Bar (1);
+ B::Baz ();
+ B::Baz (1);
+ B::Foo ();
+ B::Foo (1);
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/defarg8.C b/gcc/testsuite/g++.old-deja/g++.other/defarg8.C
new file mode 100644
index 0000000..7188209
--- /dev/null
+++ b/gcc/testsuite/g++.old-deja/g++.other/defarg8.C
@@ -0,0 +1,24 @@
+// Build don't link:
+// Special g++ options: -pedantic-errors -ansi -w
+
+// Copyright (C) 2000 Free Software Foundation, Inc.
+// Contributed by Nathan Sidwell 7 Jan 2001 <nathan@codesourcery.com>
+
+// Bug 1038. Default args on class members can produce circular dependencies.
+// Make sure we spot them, and don't depend on a particular ordering.
+
+struct AA
+{
+ static int Foo (int = Baz ()); // ERROR - candidate
+ static int Baz (int = Foo ()); // ERROR - candidate
+};
+
+int main ()
+{
+ AA::Foo (); // ERROR - no candidate
+ AA::Foo (1);
+ AA::Baz (); // ERROR - no candidate
+ AA::Baz (1);
+
+ return 0;
+}