Commit 96a1e32d by Nathan Sidwell Committed by Nathan Sidwell

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
parent 34e225a3
2001-01-11 Nathan Sidwell <nathan@codesourcery.com> 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 * pt.c (unify): Check array has a domain, before checking
whether it is variable sized. whether it is variable sized.
......
...@@ -3953,6 +3953,26 @@ convert_default_arg (type, arg, fn, parmnum) ...@@ -3953,6 +3953,26 @@ convert_default_arg (type, arg, fn, parmnum)
tree fn; tree fn;
int parmnum; 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)) if (fn && DECL_TEMPLATE_INFO (fn))
arg = tsubst_default_argument (fn, type, arg); arg = tsubst_default_argument (fn, type, arg);
......
...@@ -3874,7 +3874,6 @@ extern tree finish_method PARAMS ((tree)); ...@@ -3874,7 +3874,6 @@ extern tree finish_method PARAMS ((tree));
extern void hack_incomplete_structures PARAMS ((tree)); extern void hack_incomplete_structures PARAMS ((tree));
extern tree maybe_build_cleanup PARAMS ((tree)); extern tree maybe_build_cleanup PARAMS ((tree));
extern void finish_stmt PARAMS ((void)); 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 print_other_binding_stack PARAMS ((struct binding_level *));
extern void revert_static_member_fn PARAMS ((tree)); extern void revert_static_member_fn PARAMS ((tree));
extern void fixup_anonymous_aggr PARAMS ((tree)); extern void fixup_anonymous_aggr PARAMS ((tree));
...@@ -4085,9 +4084,6 @@ extern void compiler_error PARAMS ((const char *, ...)) ...@@ -4085,9 +4084,6 @@ extern void compiler_error PARAMS ((const char *, ...))
ATTRIBUTE_PRINTF_1; ATTRIBUTE_PRINTF_1;
extern void yyerror PARAMS ((const char *)); extern void yyerror PARAMS ((const char *));
extern void clear_inline_text_obstack PARAMS ((void)); 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 void yyhook PARAMS ((int));
extern int cp_type_qual_from_rid PARAMS ((tree)); extern int cp_type_qual_from_rid PARAMS ((tree));
...@@ -4345,6 +4341,12 @@ extern int peekyylex PARAMS ((void)); ...@@ -4345,6 +4341,12 @@ extern int peekyylex PARAMS ((void));
extern int yylex PARAMS ((void)); extern int yylex PARAMS ((void));
extern tree arbitrate_lookup PARAMS ((tree, tree, tree)); extern tree arbitrate_lookup PARAMS ((tree, tree, tree));
extern tree frob_opname PARAMS ((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 */ /* in tree.c */
extern void init_tree PARAMS ((void)); extern void init_tree PARAMS ((void));
......
...@@ -11950,20 +11950,6 @@ grokparms (first_parm) ...@@ -11950,20 +11950,6 @@ grokparms (first_parm)
return result; 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 is a constructor or overloaded `operator='. Returns non-zero if
D's arguments allow it to be a copy constructor, or copy assignment D's arguments allow it to be a copy constructor, or copy assignment
......
...@@ -2271,6 +2271,7 @@ structsp: ...@@ -2271,6 +2271,7 @@ structsp:
} }
pending_defargs pending_defargs
{ {
done_pending_defargs ();
begin_inline_definitions (); begin_inline_definitions ();
} }
pending_inlines pending_inlines
......
...@@ -164,10 +164,14 @@ char *inline_text_firstobj; ...@@ -164,10 +164,14 @@ char *inline_text_firstobj;
through and parse all of them using do_pending_defargs. Since yacc through and parse all of them using do_pending_defargs. Since yacc
parsers are not reentrant, we retain defargs state in these two parsers are not reentrant, we retain defargs state in these two
variables so that subsequent calls to do_pending_defargs can resume 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_fns; /* list of functions with unprocessed defargs */
static tree defarg_parm; 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. */ /* Initialize obstacks. Called once, from init_parse. */
...@@ -180,6 +184,8 @@ init_spew () ...@@ -180,6 +184,8 @@ init_spew ()
gcc_obstack_init (&feed_obstack); gcc_obstack_init (&feed_obstack);
ggc_add_tree_root (&defarg_fns, 1); ggc_add_tree_root (&defarg_fns, 1);
ggc_add_tree_root (&defarg_parm, 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 *), ggc_add_root (&pending_inlines, 1, sizeof (struct unparsed_text *),
mark_pending_inlines); mark_pending_inlines);
...@@ -1267,7 +1273,10 @@ add_defarg_fn (decl) ...@@ -1267,7 +1273,10 @@ add_defarg_fn (decl)
if (TREE_CODE (decl) == FUNCTION_DECL) if (TREE_CODE (decl) == FUNCTION_DECL)
TREE_VALUE (defarg_fns) = decl; TREE_VALUE (defarg_fns) = decl;
else 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. */ /* Helper for do_pending_defargs. Starts the parsing of a default arg. */
...@@ -1305,12 +1314,14 @@ do_pending_defargs () ...@@ -1305,12 +1314,14 @@ do_pending_defargs ()
if (defarg_parm) if (defarg_parm)
finish_defarg (); 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); tree defarg_fn = TREE_VALUE (defarg_fns);
if (defarg_parm == NULL_TREE) if (defarg_parm == NULL_TREE)
{ {
push_nested_class (TREE_PURPOSE (defarg_fns), 1); push_nested_class (TREE_TYPE (defarg_fns), 1);
pushlevel (0); pushlevel (0);
if (TREE_CODE (defarg_fn) == FUNCTION_DECL) if (TREE_CODE (defarg_fn) == FUNCTION_DECL)
maybe_begin_member_template_processing (defarg_fn); maybe_begin_member_template_processing (defarg_fn);
...@@ -1324,8 +1335,12 @@ do_pending_defargs () ...@@ -1324,8 +1335,12 @@ do_pending_defargs ()
defarg_parm = TREE_CHAIN (defarg_parm); defarg_parm = TREE_CHAIN (defarg_parm);
for (; defarg_parm; defarg_parm = TREE_CHAIN (defarg_parm)) for (; defarg_parm; defarg_parm = TREE_CHAIN (defarg_parm))
if (TREE_PURPOSE (defarg_parm) if (!TREE_PURPOSE (defarg_parm)
&& TREE_CODE (TREE_PURPOSE (defarg_parm)) == DEFAULT_ARG) || 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); feed_defarg (defarg_parm);
...@@ -1342,6 +1357,96 @@ do_pending_defargs () ...@@ -1342,6 +1357,96 @@ do_pending_defargs ()
poplevel (0, 0, 0); poplevel (0, 0, 0);
pop_nested_class (); 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;
} }
} }
......
2001-01-11 Nathan Sidwell <nathan@codesourcery.com> 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. * g++.old-deja/g++.pt/crash63.C: New test.
2001-01-11 Neil Booth <neil@daikokuya.demon.co.uk> 2001-01-11 Neil Booth <neil@daikokuya.demon.co.uk>
......
// 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;
}
// 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment