From 96a1e32dcdf973cab1c308cfcdfcf6f07444b2cc Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Thu, 11 Jan 2001 12:29:20 +0000 Subject: 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 --- gcc/cp/ChangeLog | 23 +++++ gcc/cp/call.c | 20 ++++ gcc/cp/cp-tree.h | 10 +- gcc/cp/decl.c | 14 --- gcc/cp/parse.y | 1 + gcc/cp/spew.c | 121 +++++++++++++++++++++++-- gcc/testsuite/ChangeLog | 9 ++ gcc/testsuite/g++.old-deja/g++.other/defarg7.C | 41 +++++++++ gcc/testsuite/g++.old-deja/g++.other/defarg8.C | 24 +++++ 9 files changed, 237 insertions(+), 26 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.other/defarg7.C create mode 100644 gcc/testsuite/g++.old-deja/g++.other/defarg8.C 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 + * 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 + * 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 + * g++.old-deja/g++.other/defarg7.C: New test. + * g++.old-deja/g++.other/defarg8.C: New test. + +2001-01-11 Nathan Sidwell + + * g++.old-deja/g++.pt/crash64.C: New test. + +2001-01-11 Nathan Sidwell + * g++.old-deja/g++.pt/crash63.C: New test. 2001-01-11 Neil Booth 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 + +// 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 + +// 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; +} -- cgit v1.1