From 72c4a4ca45bb4adc746cedd9eba5960b357b6537 Mon Sep 17 00:00:00 2001 From: Geoffrey Keating Date: Fri, 1 Dec 2006 23:01:05 +0000 Subject: [PATCH] decl.c (poplevel): Check DECL_INITIAL invariant. * decl.c (poplevel): Check DECL_INITIAL invariant. (duplicate_decls): Preserve DECL_INITIAL when eliminating a new definition in favour of an old declaration. (start_preparsed_function): Define and document value of DECL_INITIAL before and after routine. (finish_function): Check DECL_INITIAL invariant. * parser.c (cp_parser_function_definition_from_specifiers_and_declarator): Skip duplicate function definitions. From-SVN: r119427 --- gcc/cp/ChangeLog | 12 +++++++++ gcc/cp/decl.c | 69 ++++++++++++++++++++++++++++++++---------------- gcc/cp/method.c | 12 +++++---- gcc/cp/parser.c | 10 +++++++ 4 files changed, 75 insertions(+), 28 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1ecb96d1542d..989efcf06f5d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2006-12-01 Geoffrey Keating + + * decl.c (poplevel): Check DECL_INITIAL invariant. + (duplicate_decls): Preserve DECL_INITIAL when eliminating + a new definition in favour of an old declaration. + (start_preparsed_function): Define and document value of + DECL_INITIAL before and after routine. + (finish_function): Check DECL_INITIAL invariant. + * parser.c + (cp_parser_function_definition_from_specifiers_and_declarator): + Skip duplicate function definitions. + 2006-12-01 Volker Reichelt PR c++/30022 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6043596b2fd3..0852d72c7e94 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -756,7 +756,12 @@ poplevel (int keep, int reverse, int functionbody) leave_scope (); if (functionbody) - DECL_INITIAL (current_function_decl) = block; + { + /* The current function is being defined, so its DECL_INITIAL + should be error_mark_node. */ + gcc_assert (DECL_INITIAL (current_function_decl) == error_mark_node); + DECL_INITIAL (current_function_decl) = block; + } else if (block) current_binding_level->blocks = chainon (current_binding_level->blocks, block); @@ -1632,13 +1637,15 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) } /* If the new declaration is a definition, update the file and - line information on the declaration. */ + line information on the declaration, and also make + the old declaration the same definition. */ if (DECL_INITIAL (old_result) == NULL_TREE && DECL_INITIAL (new_result) != NULL_TREE) { DECL_SOURCE_LOCATION (olddecl) = DECL_SOURCE_LOCATION (old_result) = DECL_SOURCE_LOCATION (newdecl); + DECL_INITIAL (old_result) = DECL_INITIAL (new_result); if (DECL_FUNCTION_TEMPLATE_P (newdecl)) DECL_ARGUMENTS (old_result) = DECL_ARGUMENTS (new_result); @@ -10374,7 +10381,13 @@ check_function_type (tree decl, tree current_function_parms) For C++, we must first check whether that datum makes any sense. For example, "class A local_a(1,2);" means that variable local_a is an aggregate of type A, which should have a constructor - applied to it with the argument list [1, 2]. */ + applied to it with the argument list [1, 2]. + + On entry, DECL_INITIAL (decl1) should be NULL_TREE or error_mark_node, + or may be a BLOCK if the function has been defined previously + in this translation unit. On exit, DECL_INITIAL (decl1) will be + error_mark_node if the function has never been defined, or + a BLOCK if the function has been defined somewhere. */ void start_preparsed_function (tree decl1, tree attrs, int flags) @@ -10503,24 +10516,6 @@ start_preparsed_function (tree decl1, tree attrs, int flags) cp_apply_type_quals_to_decl (cp_type_quals (restype), resdecl); } - /* Initialize RTL machinery. We cannot do this until - CURRENT_FUNCTION_DECL and DECL_RESULT are set up. We do this - even when processing a template; this is how we get - CFUN set up, and our per-function variables initialized. - FIXME factor out the non-RTL stuff. */ - bl = current_binding_level; - allocate_struct_function (decl1); - current_binding_level = bl; - - /* Even though we're inside a function body, we still don't want to - call expand_expr to calculate the size of a variable-sized array. - We haven't necessarily assigned RTL to all variables yet, so it's - not safe to try to expand expressions involving them. */ - cfun->x_dont_save_pending_sizes_p = 1; - - /* Start the statement-tree, start the tree now. */ - DECL_SAVED_TREE (decl1) = push_stmt_list (); - /* Let the user know we're compiling this function. */ announce_function (decl1); @@ -10566,9 +10561,33 @@ start_preparsed_function (tree decl1, tree attrs, int flags) maybe_apply_pragma_weak (decl1); } - /* Reset these in case the call to pushdecl changed them. */ + /* Reset this in case the call to pushdecl changed it. */ current_function_decl = decl1; - cfun->decl = decl1; + + gcc_assert (DECL_INITIAL (decl1)); + + /* This function may already have been parsed, in which case just + return; our caller will skip over the body without parsing. */ + if (DECL_INITIAL (decl1) != error_mark_node) + return; + + /* Initialize RTL machinery. We cannot do this until + CURRENT_FUNCTION_DECL and DECL_RESULT are set up. We do this + even when processing a template; this is how we get + CFUN set up, and our per-function variables initialized. + FIXME factor out the non-RTL stuff. */ + bl = current_binding_level; + allocate_struct_function (decl1); + current_binding_level = bl; + + /* Even though we're inside a function body, we still don't want to + call expand_expr to calculate the size of a variable-sized array. + We haven't necessarily assigned RTL to all variables yet, so it's + not safe to try to expand expressions involving them. */ + cfun->x_dont_save_pending_sizes_p = 1; + + /* Start the statement-tree, start the tree now. */ + DECL_SAVED_TREE (decl1) = push_stmt_list (); /* If we are (erroneously) defining a function that we have already defined before, wipe out what we knew before. */ @@ -11077,6 +11096,10 @@ finish_function (int flags) which then got a warning when stored in a ptr-to-function variable. */ gcc_assert (building_stmt_tree ()); + /* The current function is being defined, so its DECL_INITIAL should + be set, and unless there's a multiple definition, it should be + error_mark_node. */ + gcc_assert (DECL_INITIAL (fndecl) == error_mark_node); /* For a cloned function, we've already got all the code we need; there's no need to add any extra bits. */ diff --git a/gcc/cp/method.c b/gcc/cp/method.c index ded0af047161..71e34f064c1a 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -407,10 +407,6 @@ use_thunk (tree thunk_fndecl, bool emit_p) } } - /* The back-end expects DECL_INITIAL to contain a BLOCK, so we - create one. */ - DECL_INITIAL (thunk_fndecl) = make_node (BLOCK); - /* Set up cloned argument trees for the thunk. */ t = NULL_TREE; for (a = DECL_ARGUMENTS (function); a; a = TREE_CHAIN (a)) @@ -424,17 +420,23 @@ use_thunk (tree thunk_fndecl, bool emit_p) } a = nreverse (t); DECL_ARGUMENTS (thunk_fndecl) = a; - BLOCK_VARS (DECL_INITIAL (thunk_fndecl)) = a; if (this_adjusting && targetm.asm_out.can_output_mi_thunk (thunk_fndecl, fixed_offset, virtual_value, alias)) { const char *fnname; + tree fn_block; + current_function_decl = thunk_fndecl; DECL_RESULT (thunk_fndecl) = build_decl (RESULT_DECL, 0, integer_type_node); fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0); + /* The back-end expects DECL_INITIAL to contain a BLOCK, so we + create one. */ + fn_block = make_node (BLOCK); + BLOCK_VARS (fn_block) = a; + DECL_INITIAL (thunk_fndecl) = fn_block; init_function_start (thunk_fndecl); current_function_is_thunk = 1; assemble_start_function (thunk_fndecl, fnname); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index ad4d454baaf1..3ed749762429 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -15583,6 +15583,16 @@ cp_parser_function_definition_from_specifiers_and_declarator cp_parser_skip_to_end_of_block_or_statement (parser); fn = error_mark_node; } + else if (DECL_INITIAL (current_function_decl) != error_mark_node) + { + /* Seen already, skip it. An error message has already been output. */ + cp_parser_skip_to_end_of_block_or_statement (parser); + fn = current_function_decl; + current_function_decl = NULL_TREE; + /* If this is a function from a class, pop the nested class. */ + if (current_class_name) + pop_nested_class (); + } else fn = cp_parser_function_definition_after_declarator (parser, /*inline_p=*/false);