diff options
Diffstat (limited to 'contrib/gcc/cp/semantics.c')
-rw-r--r-- | contrib/gcc/cp/semantics.c | 2558 |
1 files changed, 1475 insertions, 1083 deletions
diff --git a/contrib/gcc/cp/semantics.c b/contrib/gcc/cp/semantics.c index 110eb3a..966b004 100644 --- a/contrib/gcc/cp/semantics.c +++ b/contrib/gcc/cp/semantics.c @@ -3,29 +3,32 @@ building RTL. These routines are used both during actual parsing and during the instantiation of template functions. - Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Copyright (C) 1998, 1999, 2000, 2001, 2002, + 2003, 2004 Free Software Foundation, Inc. Written by Mark Mitchell (mmitchell@usa.net) based on code found formerly in parse.y and pt.c. - This file is part of GNU CC. + This file is part of GCC. - GNU CC is free software; you can redistribute it and/or modify it + GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. - GNU CC is distributed in the hope that it will be useful, but + GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with GNU CC; see the file COPYING. If not, write to the Free + along with GCC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.h" #include "tree.h" #include "cp-tree.h" #include "tree-inline.h" @@ -33,12 +36,12 @@ #include "lex.h" #include "toplev.h" #include "flags.h" -#include "ggc.h" #include "rtl.h" #include "expr.h" #include "output.h" #include "timevar.h" #include "debug.h" +#include "cgraph.h" /* There routines provide a modular interface to perform many parsing operations. They may therefore be used during actual parsing, or @@ -49,18 +52,14 @@ parsing into this file; that will make implementing the new parser much easier since it will be able to make use of these routines. */ -static tree maybe_convert_cond PARAMS ((tree)); -static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *)); -static void deferred_type_access_control PARAMS ((void)); -static void emit_associated_thunks PARAMS ((tree)); -static void genrtl_try_block PARAMS ((tree)); -static void genrtl_eh_spec_block PARAMS ((tree)); -static void genrtl_handler PARAMS ((tree)); -static void genrtl_named_return_value PARAMS ((void)); -static void cp_expand_stmt PARAMS ((tree)); -static void genrtl_start_function PARAMS ((tree)); -static void genrtl_finish_function PARAMS ((tree)); -static tree clear_decl_rtl PARAMS ((tree *, int *, void *)); +static tree maybe_convert_cond (tree); +static tree simplify_aggr_init_exprs_r (tree *, int *, void *); +static void emit_associated_thunks (tree); +static void genrtl_try_block (tree); +static void genrtl_eh_spec_block (tree); +static void genrtl_handler (tree); +static void cp_expand_stmt (tree); + /* Finish processing the COND, the SUBSTMT condition for STMT. */ @@ -79,12 +78,233 @@ static tree clear_decl_rtl PARAMS ((tree *, int *, void *)); (SUBSTMT) = (COND); \ } while (0) +/* Deferred Access Checking Overview + --------------------------------- + + Most C++ expressions and declarations require access checking + to be performed during parsing. However, in several cases, + this has to be treated differently. + + For member declarations, access checking has to be deferred + until more information about the declaration is known. For + example: + + class A { + typedef int X; + public: + X f(); + }; + + A::X A::f(); + A::X g(); + + When we are parsing the function return type `A::X', we don't + really know if this is allowed until we parse the function name. + + Furthermore, some contexts require that access checking is + never performed at all. These include class heads, and template + instantiations. + + Typical use of access checking functions is described here: + + 1. When we enter a context that requires certain access checking + mode, the function `push_deferring_access_checks' is called with + DEFERRING argument specifying the desired mode. Access checking + may be performed immediately (dk_no_deferred), deferred + (dk_deferred), or not performed (dk_no_check). + + 2. When a declaration such as a type, or a variable, is encountered, + the function `perform_or_defer_access_check' is called. It + maintains a TREE_LIST of all deferred checks. + + 3. The global `current_class_type' or `current_function_decl' is then + setup by the parser. `enforce_access' relies on these information + to check access. + + 4. Upon exiting the context mentioned in step 1, + `perform_deferred_access_checks' is called to check all declaration + stored in the TREE_LIST. `pop_deferring_access_checks' is then + called to restore the previous access checking mode. + + In case of parsing error, we simply call `pop_deferring_access_checks' + without `perform_deferred_access_checks'. */ + +/* Data for deferred access checking. */ +static GTY(()) deferred_access *deferred_access_stack; +static GTY(()) deferred_access *deferred_access_free_list; + +/* Save the current deferred access states and start deferred + access checking iff DEFER_P is true. */ + +void +push_deferring_access_checks (deferring_kind deferring) +{ + deferred_access *d; + + /* For context like template instantiation, access checking + disabling applies to all nested context. */ + if (deferred_access_stack + && deferred_access_stack->deferring_access_checks_kind == dk_no_check) + deferring = dk_no_check; + + /* Recycle previously used free store if available. */ + if (deferred_access_free_list) + { + d = deferred_access_free_list; + deferred_access_free_list = d->next; + } + else + d = ggc_alloc (sizeof (deferred_access)); + + d->next = deferred_access_stack; + d->deferred_access_checks = NULL_TREE; + d->deferring_access_checks_kind = deferring; + deferred_access_stack = d; +} + +/* Resume deferring access checks again after we stopped doing + this previously. */ + +void +resume_deferring_access_checks (void) +{ + if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred) + deferred_access_stack->deferring_access_checks_kind = dk_deferred; +} + +/* Stop deferring access checks. */ + +void +stop_deferring_access_checks (void) +{ + if (deferred_access_stack->deferring_access_checks_kind == dk_deferred) + deferred_access_stack->deferring_access_checks_kind = dk_no_deferred; +} + +/* Discard the current deferred access checks and restore the + previous states. */ + +void +pop_deferring_access_checks (void) +{ + deferred_access *d = deferred_access_stack; + deferred_access_stack = d->next; + + /* Remove references to access checks TREE_LIST. */ + d->deferred_access_checks = NULL_TREE; + + /* Store in free list for later use. */ + d->next = deferred_access_free_list; + deferred_access_free_list = d; +} + +/* Returns a TREE_LIST representing the deferred checks. + The TREE_PURPOSE of each node is the type through which the + access occurred; the TREE_VALUE is the declaration named. + */ + +tree +get_deferred_access_checks (void) +{ + return deferred_access_stack->deferred_access_checks; +} + +/* Take current deferred checks and combine with the + previous states if we also defer checks previously. + Otherwise perform checks now. */ + +void +pop_to_parent_deferring_access_checks (void) +{ + tree deferred_check = get_deferred_access_checks (); + deferred_access *d1 = deferred_access_stack; + deferred_access *d2 = deferred_access_stack->next; + deferred_access *d3 = deferred_access_stack->next->next; + + /* Temporary swap the order of the top two states, just to make + sure the garbage collector will not reclaim the memory during + processing below. */ + deferred_access_stack = d2; + d2->next = d1; + d1->next = d3; + + for ( ; deferred_check; deferred_check = TREE_CHAIN (deferred_check)) + /* Perform deferred check if required. */ + perform_or_defer_access_check (TREE_PURPOSE (deferred_check), + TREE_VALUE (deferred_check)); + + deferred_access_stack = d1; + d1->next = d2; + d2->next = d3; + pop_deferring_access_checks (); +} + +/* Perform the deferred access checks. + + After performing the checks, we still have to keep the list + `deferred_access_stack->deferred_access_checks' since we may want + to check access for them again later in a different context. + For example: + + class A { + typedef int X; + static X a; + }; + A::X A::a, x; // No error for `A::a', error for `x' + + We have to perform deferred access of `A::X', first with `A::a', + next with `x'. */ + +void +perform_deferred_access_checks (void) +{ + tree deferred_check; + for (deferred_check = deferred_access_stack->deferred_access_checks; + deferred_check; + deferred_check = TREE_CHAIN (deferred_check)) + /* Check access. */ + enforce_access (TREE_PURPOSE (deferred_check), + TREE_VALUE (deferred_check)); +} + +/* Defer checking the accessibility of DECL, when looked up in + BINFO. */ + +void +perform_or_defer_access_check (tree binfo, tree decl) +{ + tree check; + + my_friendly_assert (TREE_CODE (binfo) == TREE_VEC, 20030623); + + /* If we are not supposed to defer access checks, just check now. */ + if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred) + { + enforce_access (binfo, decl); + return; + } + /* Exit if we are in a context that no access checking is performed. */ + else if (deferred_access_stack->deferring_access_checks_kind == dk_no_check) + return; + + /* See if we are already going to perform this check. */ + for (check = deferred_access_stack->deferred_access_checks; + check; + check = TREE_CHAIN (check)) + if (TREE_VALUE (check) == decl && TREE_PURPOSE (check) == binfo) + return; + /* If not, record the check. */ + deferred_access_stack->deferred_access_checks + = tree_cons (binfo, decl, + deferred_access_stack->deferred_access_checks); +} + /* Returns nonzero if the current statement is a full expression, i.e. temporaries created during that statement should be destroyed at the end of the statement. */ int -stmts_are_full_exprs_p () +stmts_are_full_exprs_p (void) { return current_stmt_tree ()->stmts_are_full_exprs_p; } @@ -94,7 +314,7 @@ stmts_are_full_exprs_p () returned. */ stmt_tree -current_stmt_tree () +current_stmt_tree (void) { return (cfun ? &cfun->language->base.x_stmt_tree @@ -106,8 +326,7 @@ current_stmt_tree () declared is not an anonymous union" [class.union]. */ int -anon_aggr_type_p (node) - tree node; +anon_aggr_type_p (tree node) { return ANON_AGGR_TYPE_P (node); } @@ -115,7 +334,7 @@ anon_aggr_type_p (node) /* Finish a scope. */ tree -do_poplevel () +do_poplevel (void) { tree block = NULL_TREE; @@ -123,14 +342,17 @@ do_poplevel () { tree scope_stmts = NULL_TREE; - if (!processing_template_decl) - scope_stmts = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); - block = poplevel (kept_level_p (), 1, 0); - if (block && !processing_template_decl) + if (!processing_template_decl) { - SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block; - SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block; + /* This needs to come after the poplevel so that partial scopes + are properly nested. */ + scope_stmts = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); + if (block) + { + SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block; + SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block; + } } } @@ -140,21 +362,20 @@ do_poplevel () /* Begin a new scope. */ void -do_pushlevel () +do_pushlevel (scope_kind sk) { if (stmts_are_full_exprs_p ()) { - pushlevel (0); if (!processing_template_decl) add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0); + begin_scope (sk, NULL); } } /* Finish a goto-statement. */ tree -finish_goto_stmt (destination) - tree destination; +finish_goto_stmt (tree destination) { if (TREE_CODE (destination) == IDENTIFIER_NODE) destination = lookup_label (destination); @@ -163,13 +384,17 @@ finish_goto_stmt (destination) mark the used labels as used. */ if (TREE_CODE (destination) == LABEL_DECL) TREE_USED (destination) = 1; - - if (TREE_CODE (destination) != LABEL_DECL) - /* We don't inline calls to functions with computed gotos. - Those functions are typically up to some funny business, - and may be depending on the labels being at particular - addresses, or some such. */ - DECL_UNINLINABLE (current_function_decl) = 1; + else + { + /* The DESTINATION is being used as an rvalue. */ + if (!processing_template_decl) + destination = decay_conversion (destination); + /* We don't inline calls to functions with computed gotos. + Those functions are typically up to some funny business, + and may be depending on the labels being at particular + addresses, or some such. */ + DECL_UNINLINABLE (current_function_decl) = 1; + } check_goto (destination); @@ -179,9 +404,8 @@ finish_goto_stmt (destination) /* COND is the condition-expression for an if, while, etc., statement. Convert it to a boolean value, if appropriate. */ -tree -maybe_convert_cond (cond) - tree cond; +static tree +maybe_convert_cond (tree cond) { /* Empty conditions remain empty. */ if (!cond) @@ -199,36 +423,22 @@ maybe_convert_cond (cond) /* Finish an expression-statement, whose EXPRESSION is as indicated. */ tree -finish_expr_stmt (expr) - tree expr; +finish_expr_stmt (tree expr) { tree r = NULL_TREE; - tree expr_type = NULL_TREE;; if (expr != NULL_TREE) { - if (!processing_template_decl - && !(stmts_are_full_exprs_p ()) - && ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE - && lvalue_p (expr)) - || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)) - expr = default_conversion (expr); - - /* Remember the type of the expression. */ - expr_type = TREE_TYPE (expr); - - if (stmts_are_full_exprs_p ()) + if (!processing_template_decl) expr = convert_to_void (expr, "statement"); + else if (!type_dependent_expression_p (expr)) + convert_to_void (build_non_dependent_expr (expr), "statement"); r = add_stmt (build_stmt (EXPR_STMT, expr)); } finish_stmt (); - /* This was an expression-statement, so we save the type of the - expression. */ - last_expr_type = expr_type; - return r; } @@ -237,10 +447,10 @@ finish_expr_stmt (expr) appropriate. */ tree -begin_if_stmt () +begin_if_stmt (void) { tree r; - do_pushlevel (); + do_pushlevel (sk_block); r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE); add_stmt (r); return r; @@ -250,9 +460,7 @@ begin_if_stmt () IF_STMT. */ void -finish_if_stmt_cond (cond, if_stmt) - tree cond; - tree if_stmt; +finish_if_stmt_cond (tree cond, tree if_stmt) { cond = maybe_convert_cond (cond); FINISH_COND (cond, if_stmt, IF_COND (if_stmt)); @@ -262,8 +470,7 @@ finish_if_stmt_cond (cond, if_stmt) IF_STMT. */ tree -finish_then_clause (if_stmt) - tree if_stmt; +finish_then_clause (tree if_stmt) { RECHAIN_STMTS (if_stmt, THEN_CLAUSE (if_stmt)); return if_stmt; @@ -272,7 +479,7 @@ finish_then_clause (if_stmt) /* Begin the else-clause of an if-statement. */ void -begin_else_clause () +begin_else_clause (void) { } @@ -280,8 +487,7 @@ begin_else_clause () IF_STMT. */ void -finish_else_clause (if_stmt) - tree if_stmt; +finish_else_clause (tree if_stmt) { RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt)); } @@ -289,7 +495,7 @@ finish_else_clause (if_stmt) /* Finish an if-statement. */ void -finish_if_stmt () +finish_if_stmt (void) { finish_stmt (); do_poplevel (); @@ -299,12 +505,12 @@ finish_if_stmt () appropriate. */ tree -begin_while_stmt () +begin_while_stmt (void) { tree r; r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE); add_stmt (r); - do_pushlevel (); + do_pushlevel (sk_block); return r; } @@ -312,9 +518,7 @@ begin_while_stmt () WHILE_STMT. */ void -finish_while_stmt_cond (cond, while_stmt) - tree cond; - tree while_stmt; +finish_while_stmt_cond (tree cond, tree while_stmt) { cond = maybe_convert_cond (cond); if (processing_template_decl) @@ -345,8 +549,7 @@ finish_while_stmt_cond (cond, while_stmt) /* Finish a while-statement, which may be given by WHILE_STMT. */ void -finish_while_stmt (while_stmt) - tree while_stmt; +finish_while_stmt (tree while_stmt) { do_poplevel (); RECHAIN_STMTS (while_stmt, WHILE_BODY (while_stmt)); @@ -357,7 +560,7 @@ finish_while_stmt (while_stmt) appropriate. */ tree -begin_do_stmt () +begin_do_stmt (void) { tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE); add_stmt (r); @@ -367,8 +570,7 @@ begin_do_stmt () /* Finish the body of a do-statement, which may be given by DO_STMT. */ void -finish_do_body (do_stmt) - tree do_stmt; +finish_do_body (tree do_stmt) { RECHAIN_STMTS (do_stmt, DO_BODY (do_stmt)); } @@ -377,9 +579,7 @@ finish_do_body (do_stmt) COND is as indicated. */ void -finish_do_stmt (cond, do_stmt) - tree cond; - tree do_stmt; +finish_do_stmt (tree cond, tree do_stmt) { cond = maybe_convert_cond (cond); DO_COND (do_stmt) = cond; @@ -390,13 +590,11 @@ finish_do_stmt (cond, do_stmt) indicated. */ tree -finish_return_stmt (expr) - tree expr; +finish_return_stmt (tree expr) { tree r; - if (!processing_template_decl) - expr = check_return_expr (expr); + expr = check_return_expr (expr); if (!processing_template_decl) { if (DECL_DESTRUCTOR_P (current_function_decl)) @@ -417,7 +615,7 @@ finish_return_stmt (expr) /* Begin a for-statement. Returns a new FOR_STMT if appropriate. */ tree -begin_for_stmt () +begin_for_stmt (void) { tree r; @@ -425,10 +623,7 @@ begin_for_stmt () NULL_TREE, NULL_TREE); NEW_FOR_SCOPE_P (r) = flag_new_for_scope > 0; if (NEW_FOR_SCOPE_P (r)) - { - do_pushlevel (); - note_level_for_for (); - } + do_pushlevel (sk_for); add_stmt (r); return r; @@ -438,21 +633,18 @@ begin_for_stmt () given by FOR_STMT. */ void -finish_for_init_stmt (for_stmt) - tree for_stmt; +finish_for_init_stmt (tree for_stmt) { if (last_tree != for_stmt) RECHAIN_STMTS (for_stmt, FOR_INIT_STMT (for_stmt)); - do_pushlevel (); + do_pushlevel (sk_block); } /* Finish the COND of a for-statement, which may be given by FOR_STMT. */ void -finish_for_cond (cond, for_stmt) - tree cond; - tree for_stmt; +finish_for_cond (tree cond, tree for_stmt) { cond = maybe_convert_cond (cond); if (processing_template_decl) @@ -484,10 +676,15 @@ finish_for_cond (cond, for_stmt) given by FOR_STMT. */ void -finish_for_expr (expr, for_stmt) - tree expr; - tree for_stmt; +finish_for_expr (tree expr, tree for_stmt) { + /* If EXPR is an overloaded function, issue an error; there is no + context available to use to perform overload resolution. */ + if (expr && type_unknown_p (expr)) + { + cxx_incomplete_type_error (expr, TREE_TYPE (expr)); + expr = error_mark_node; + } FOR_EXPR (for_stmt) = expr; } @@ -496,8 +693,7 @@ finish_for_expr (expr, for_stmt) provided. */ void -finish_for_stmt (for_stmt) - tree for_stmt; +finish_for_stmt (tree for_stmt) { /* Pop the scope for the body of the loop. */ do_poplevel (); @@ -510,7 +706,7 @@ finish_for_stmt (for_stmt) /* Finish a break-statement. */ tree -finish_break_stmt () +finish_break_stmt (void) { return add_stmt (build_break_stmt ()); } @@ -518,7 +714,7 @@ finish_break_stmt () /* Finish a continue-statement. */ tree -finish_continue_stmt () +finish_continue_stmt (void) { return add_stmt (build_continue_stmt ()); } @@ -527,10 +723,10 @@ finish_continue_stmt () appropriate. */ tree -begin_switch_stmt () +begin_switch_stmt (void) { tree r; - do_pushlevel (); + do_pushlevel (sk_block); r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE); add_stmt (r); return r; @@ -539,9 +735,7 @@ begin_switch_stmt () /* Finish the cond of a switch-statement. */ void -finish_switch_cond (cond, switch_stmt) - tree cond; - tree switch_stmt; +finish_switch_cond (tree cond, tree switch_stmt) { tree orig_type = NULL; if (!processing_template_decl) @@ -549,7 +743,7 @@ finish_switch_cond (cond, switch_stmt) tree index; /* Convert the condition to an integer or enumeration type. */ - cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, 1); + cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, true); if (cond == NULL_TREE) { error ("switch quantity not an integer"); @@ -558,7 +752,10 @@ finish_switch_cond (cond, switch_stmt) orig_type = TREE_TYPE (cond); if (cond != error_mark_node) { - cond = default_conversion (cond); + /* [stmt.switch] + + Integral promotions are performed. */ + cond = perform_integral_promotions (cond); cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond)); } @@ -583,8 +780,7 @@ finish_switch_cond (cond, switch_stmt) SWITCH_STMT. The COND to switch on is indicated. */ void -finish_switch_stmt (switch_stmt) - tree switch_stmt; +finish_switch_stmt (tree switch_stmt) { RECHAIN_STMTS (switch_stmt, SWITCH_BODY (switch_stmt)); pop_switch (); @@ -595,8 +791,7 @@ finish_switch_stmt (switch_stmt) /* Generate the RTL for T, which is a TRY_BLOCK. */ static void -genrtl_try_block (t) - tree t; +genrtl_try_block (tree t) { if (CLEANUP_P (t)) { @@ -607,7 +802,7 @@ genrtl_try_block (t) else { if (!FN_TRY_BLOCK_P (t)) - emit_line_note (input_filename, lineno); + emit_line_note (input_location); expand_eh_region_start (); expand_stmt (TRY_STMTS (t)); @@ -632,8 +827,7 @@ genrtl_try_block (t) /* Generate the RTL for T, which is an EH_SPEC_BLOCK. */ static void -genrtl_eh_spec_block (t) - tree t; +genrtl_eh_spec_block (tree t) { expand_eh_region_start (); expand_stmt (EH_SPEC_STMTS (t)); @@ -648,7 +842,7 @@ genrtl_eh_spec_block (t) appropriate. */ tree -begin_try_block () +begin_try_block (void) { tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE); add_stmt (r); @@ -658,7 +852,7 @@ begin_try_block () /* Likewise, for a function-try-block. */ tree -begin_function_try_block () +begin_function_try_block (void) { tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE); FN_TRY_BLOCK_P (r) = 1; @@ -669,8 +863,7 @@ begin_function_try_block () /* Finish a try-block, which may be given by TRY_BLOCK. */ void -finish_try_block (try_block) - tree try_block; +finish_try_block (tree try_block) { RECHAIN_STMTS (try_block, TRY_STMTS (try_block)); } @@ -679,8 +872,7 @@ finish_try_block (try_block) TRY_BLOCK. */ void -finish_cleanup_try_block (try_block) - tree try_block; +finish_cleanup_try_block (tree try_block) { RECHAIN_STMTS (try_block, TRY_STMTS (try_block)); } @@ -689,9 +881,7 @@ finish_cleanup_try_block (try_block) by CLEANUP. */ void -finish_cleanup (cleanup, try_block) - tree cleanup; - tree try_block; +finish_cleanup (tree cleanup, tree try_block) { TRY_HANDLERS (try_block) = cleanup; CLEANUP_P (try_block) = 1; @@ -700,8 +890,7 @@ finish_cleanup (cleanup, try_block) /* Likewise, for a function-try-block. */ void -finish_function_try_block (try_block) - tree try_block; +finish_function_try_block (tree try_block) { if (TREE_CHAIN (try_block) && TREE_CODE (TREE_CHAIN (try_block)) == CTOR_INITIALIZER) @@ -720,8 +909,7 @@ finish_function_try_block (try_block) TRY_BLOCK. */ void -finish_handler_sequence (try_block) - tree try_block; +finish_handler_sequence (tree try_block) { RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block)); check_handlers (TRY_HANDLERS (try_block)); @@ -730,8 +918,7 @@ finish_handler_sequence (try_block) /* Likewise, for a function-try-block. */ void -finish_function_handler_sequence (try_block) - tree try_block; +finish_function_handler_sequence (tree try_block) { in_function_try_handler = 0; RECHAIN_STMTS (try_block, TRY_HANDLERS (try_block)); @@ -741,8 +928,7 @@ finish_function_handler_sequence (try_block) /* Generate the RTL for T, which is a HANDLER. */ static void -genrtl_handler (t) - tree t; +genrtl_handler (tree t) { genrtl_do_pushlevel (); if (!processing_template_decl) @@ -755,15 +941,14 @@ genrtl_handler (t) /* Begin a handler. Returns a HANDLER if appropriate. */ tree -begin_handler () +begin_handler (void) { tree r; r = build_stmt (HANDLER, NULL_TREE, NULL_TREE); add_stmt (r); /* Create a binding level for the eh_info and the exception object cleanup. */ - do_pushlevel (); - note_level_for_catch (); + do_pushlevel (sk_catch); return r; } @@ -772,9 +957,7 @@ begin_handler () if this is a `catch (...)' clause. */ void -finish_handler_parms (decl, handler) - tree decl; - tree handler; +finish_handler_parms (tree decl, tree handler) { tree type = NULL_TREE; if (processing_template_decl) @@ -792,14 +975,15 @@ finish_handler_parms (decl, handler) type = expand_start_catch_block (decl); HANDLER_TYPE (handler) = type; + if (!processing_template_decl && type) + mark_used (eh_type_info (type)); } /* Finish a handler, which may be given by HANDLER. The BLOCKs are the return value from the matching call to finish_handler_parms. */ void -finish_handler (handler) - tree handler; +finish_handler (tree handler) { if (!processing_template_decl) expand_end_catch_block (); @@ -807,13 +991,12 @@ finish_handler (handler) RECHAIN_STMTS (handler, HANDLER_BODY (handler)); } -/* Begin a compound-statement. If HAS_NO_SCOPE is nonzero, the +/* Begin a compound-statement. If HAS_NO_SCOPE is true, the compound-statement does not define a scope. Returns a new - COMPOUND_STMT if appropriate. */ + COMPOUND_STMT. */ tree -begin_compound_stmt (has_no_scope) - int has_no_scope; +begin_compound_stmt (bool has_no_scope) { tree r; int is_try = 0; @@ -830,37 +1013,29 @@ begin_compound_stmt (has_no_scope) last_expr_type = NULL_TREE; if (!has_no_scope) - { - do_pushlevel (); - if (is_try) - note_level_for_try (); - } + do_pushlevel (is_try ? sk_try : sk_block); else /* Normally, we try hard to keep the BLOCK for a statement-expression. But, if it's a statement-expression with a scopeless block, there's nothing to keep, and we don't want to accidentally keep a block *inside* the scopeless block. */ - keep_next_level (0); + keep_next_level (false); return r; } -/* Finish a compound-statement, which may be given by COMPOUND_STMT. - If HAS_NO_SCOPE is nonzero, the compound statement does not define - a scope. */ +/* Finish a compound-statement, which is given by COMPOUND_STMT. */ tree -finish_compound_stmt (has_no_scope, compound_stmt) - int has_no_scope; - tree compound_stmt; +finish_compound_stmt (tree compound_stmt) { tree r; tree t; - if (!has_no_scope) - r = do_poplevel (); - else + if (COMPOUND_STMT_NO_SCOPE (compound_stmt)) r = NULL_TREE; + else + r = do_poplevel (); RECHAIN_STMTS (compound_stmt, COMPOUND_BODY (compound_stmt)); @@ -880,13 +1055,11 @@ finish_compound_stmt (has_no_scope, compound_stmt) CLOBBERS. */ tree -finish_asm_stmt (cv_qualifier, string, output_operands, - input_operands, clobbers) - tree cv_qualifier; - tree string; - tree output_operands; - tree input_operands; - tree clobbers; +finish_asm_stmt (tree cv_qualifier, + tree string, + tree output_operands, + tree input_operands, + tree clobbers) { tree r; tree t; @@ -943,9 +1116,9 @@ finish_asm_stmt (cv_qualifier, string, output_operands, &allows_reg, &is_inout)) { - /* By marking the type as erroneous, we will not try to - process this operand again in expand_asm_operands. */ - TREE_TYPE (operand) = error_mark_node; + /* By marking this operand as erroneous, we will not try + to process this operand again in expand_asm_operands. */ + TREE_VALUE (t) = error_mark_node; continue; } @@ -968,12 +1141,11 @@ finish_asm_stmt (cv_qualifier, string, output_operands, /* Finish a label with the indicated NAME. */ -void -finish_label_stmt (name) - tree name; +tree +finish_label_stmt (tree name) { - tree decl = define_label (input_filename, lineno, name); - add_stmt (build_stmt (LABEL_STMT, decl)); + tree decl = define_label (input_location, name); + return add_stmt (build_stmt (LABEL_STMT, decl)); } /* Finish a series of declarations for local labels. G++ allows users @@ -981,8 +1153,7 @@ finish_label_stmt (name) is useful when writing code involving statement-expressions. */ void -finish_label_decl (name) - tree name; +finish_label_decl (tree name) { tree decl = declare_local_label (name); add_decl_stmt (decl); @@ -991,9 +1162,7 @@ finish_label_decl (name) /* When DECL goes out of scope, make sure that CLEANUP is executed. */ void -finish_decl_cleanup (decl, cleanup) - tree decl; - tree cleanup; +finish_decl_cleanup (tree decl, tree cleanup) { add_stmt (build_stmt (CLEANUP_STMT, decl, cleanup)); } @@ -1001,105 +1170,13 @@ finish_decl_cleanup (decl, cleanup) /* If the current scope exits with an exception, run CLEANUP. */ void -finish_eh_cleanup (cleanup) - tree cleanup; +finish_eh_cleanup (tree cleanup) { tree r = build_stmt (CLEANUP_STMT, NULL_TREE, cleanup); CLEANUP_EH_ONLY (r) = 1; add_stmt (r); } -/* Generate the RTL for a RETURN_INIT. */ - -static void -genrtl_named_return_value () -{ - tree decl = DECL_RESULT (current_function_decl); - - /* If this named return value comes in a register, put it in a - pseudo-register. */ - if (DECL_REGISTER (decl)) - { - /* Note that the mode of the old DECL_RTL may be wider than the - mode of DECL_RESULT, depending on the calling conventions for - the processor. For example, on the Alpha, a 32-bit integer - is returned in a DImode register -- the DECL_RESULT has - SImode but the DECL_RTL for the DECL_RESULT has DImode. So, - here, we use the mode the back-end has already assigned for - the return value. */ - SET_DECL_RTL (decl, gen_reg_rtx (GET_MODE (DECL_RTL (decl)))); - if (TREE_ADDRESSABLE (decl)) - put_var_into_stack (decl, /*rescan=*/true); - } - - emit_local_var (decl); -} - -/* Bind a name and initialization to the return value of - the current function. */ - -void -finish_named_return_value (return_id, init) - tree return_id, init; -{ - tree decl = DECL_RESULT (current_function_decl); - - /* Give this error as many times as there are occurrences, so that - users can use Emacs compilation buffers to find and fix all such - places. */ - if (pedantic) - pedwarn ("ISO C++ does not permit named return values"); - cp_deprecated ("the named return value extension"); - - if (return_id != NULL_TREE) - { - if (DECL_NAME (decl) == NULL_TREE) - DECL_NAME (decl) = return_id; - else - { - error ("return identifier `%D' already in place", return_id); - return; - } - } - - /* Can't let this happen for constructors. */ - if (DECL_CONSTRUCTOR_P (current_function_decl)) - { - error ("can't redefine default return value for constructors"); - return; - } - - /* If we have a named return value, put that in our scope as well. */ - if (DECL_NAME (decl) != NULL_TREE) - { - /* Let `cp_finish_decl' know that this initializer is ok. */ - DECL_INITIAL (decl) = init; - if (doing_semantic_analysis_p ()) - pushdecl (decl); - if (!processing_template_decl) - { - cp_finish_decl (decl, init, NULL_TREE, 0); - add_stmt (build_stmt (RETURN_INIT, NULL_TREE, NULL_TREE)); - } - else - add_stmt (build_stmt (RETURN_INIT, return_id, init)); - } - - /* Don't use tree-inlining for functions with named return values. - That doesn't work properly because we don't do any translation of - the RETURN_INITs when they are copied. */ - DECL_UNINLINABLE (current_function_decl) = 1; -} - -/* Begin processing a mem-initializer-list. */ - -void -begin_mem_initializers () -{ - if (! DECL_CONSTRUCTOR_P (current_function_decl)) - error ("only constructors take base initializers"); -} - /* The MEM_INITS is a list of mem-initializers, in reverse of the order they were written by the user. Each node is as for emit_mem_initializers. */ @@ -1120,7 +1197,7 @@ finish_mem_initializers (tree mem_inits) /* Returns the stack of SCOPE_STMTs for the current function. */ tree * -current_scope_stmt_stack () +current_scope_stmt_stack (void) { return &cfun->language->base.x_scope_stmt_stack; } @@ -1128,8 +1205,7 @@ current_scope_stmt_stack () /* Finish a parenthesized expression EXPR. */ tree -finish_parenthesized_expr (expr) - tree expr; +finish_parenthesized_expr (tree expr) { if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (expr)))) /* This inhibits warnings in c_common_truthvalue_conversion. */ @@ -1142,11 +1218,209 @@ finish_parenthesized_expr (expr) return expr; } +/* Finish a reference to a non-static data member (DECL) that is not + preceded by `.' or `->'. */ + +tree +finish_non_static_data_member (tree decl, tree object, tree qualifying_scope) +{ + my_friendly_assert (TREE_CODE (decl) == FIELD_DECL, 20020909); + + if (!object) + { + if (current_function_decl + && DECL_STATIC_FUNCTION_P (current_function_decl)) + cp_error_at ("invalid use of member `%D' in static member function", + decl); + else + cp_error_at ("invalid use of non-static data member `%D'", decl); + error ("from this location"); + + return error_mark_node; + } + TREE_USED (current_class_ptr) = 1; + if (processing_template_decl && !qualifying_scope) + { + tree type = TREE_TYPE (decl); + + if (TREE_CODE (type) == REFERENCE_TYPE) + type = TREE_TYPE (type); + else + { + /* Set the cv qualifiers. */ + int quals = cp_type_quals (TREE_TYPE (current_class_ref)); + + if (DECL_MUTABLE_P (decl)) + quals &= ~TYPE_QUAL_CONST; + + quals |= cp_type_quals (TREE_TYPE (decl)); + type = cp_build_qualified_type (type, quals); + } + + return build_min (COMPONENT_REF, type, object, decl); + } + else + { + tree access_type = TREE_TYPE (object); + tree lookup_context = context_for_name_lookup (decl); + + while (!DERIVED_FROM_P (lookup_context, access_type)) + { + access_type = TYPE_CONTEXT (access_type); + while (access_type && DECL_P (access_type)) + access_type = DECL_CONTEXT (access_type); + + if (!access_type) + { + cp_error_at ("object missing in reference to `%D'", decl); + error ("from this location"); + return error_mark_node; + } + } + + /* If PROCESSING_TEMPLATE_DECL is nonzero here, then + QUALIFYING_SCOPE is also non-null. Wrap this in a SCOPE_REF + for now. */ + if (processing_template_decl) + return build_min (SCOPE_REF, TREE_TYPE (decl), + qualifying_scope, DECL_NAME (decl)); + + perform_or_defer_access_check (TYPE_BINFO (access_type), decl); + + /* If the data member was named `C::M', convert `*this' to `C' + first. */ + if (qualifying_scope) + { + tree binfo = NULL_TREE; + object = build_scoped_ref (object, qualifying_scope, + &binfo); + } + + return build_class_member_access_expr (object, decl, + /*access_path=*/NULL_TREE, + /*preserve_reference=*/false); + } +} + +/* DECL was the declaration to which a qualified-id resolved. Issue + an error message if it is not accessible. If OBJECT_TYPE is + non-NULL, we have just seen `x->' or `x.' and OBJECT_TYPE is the + type of `*x', or `x', respectively. If the DECL was named as + `A::B' then NESTED_NAME_SPECIFIER is `A'. */ + +void +check_accessibility_of_qualified_id (tree decl, + tree object_type, + tree nested_name_specifier) +{ + tree scope; + tree qualifying_type = NULL_TREE; + + /* Determine the SCOPE of DECL. */ + scope = context_for_name_lookup (decl); + /* If the SCOPE is not a type, then DECL is not a member. */ + if (!TYPE_P (scope)) + return; + /* Compute the scope through which DECL is being accessed. */ + if (object_type + /* OBJECT_TYPE might not be a class type; consider: + + class A { typedef int I; }; + I *p; + p->A::I::~I(); + + In this case, we will have "A::I" as the DECL, but "I" as the + OBJECT_TYPE. */ + && CLASS_TYPE_P (object_type) + && DERIVED_FROM_P (scope, object_type)) + /* If we are processing a `->' or `.' expression, use the type of the + left-hand side. */ + qualifying_type = object_type; + else if (nested_name_specifier) + { + /* If the reference is to a non-static member of the + current class, treat it as if it were referenced through + `this'. */ + if (DECL_NONSTATIC_MEMBER_P (decl) + && current_class_ptr + && DERIVED_FROM_P (scope, current_class_type)) + qualifying_type = current_class_type; + /* Otherwise, use the type indicated by the + nested-name-specifier. */ + else + qualifying_type = nested_name_specifier; + } + else + /* Otherwise, the name must be from the current class or one of + its bases. */ + qualifying_type = currently_open_derived_class (scope); + + if (qualifying_type) + perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl); +} + +/* EXPR is the result of a qualified-id. The QUALIFYING_CLASS was the + class named to the left of the "::" operator. DONE is true if this + expression is a complete postfix-expression; it is false if this + expression is followed by '->', '[', '(', etc. ADDRESS_P is true + iff this expression is the operand of '&'. */ + +tree +finish_qualified_id_expr (tree qualifying_class, tree expr, bool done, + bool address_p) +{ + if (error_operand_p (expr)) + return error_mark_node; + + /* If EXPR occurs as the operand of '&', use special handling that + permits a pointer-to-member. */ + if (address_p && done) + { + if (TREE_CODE (expr) == SCOPE_REF) + expr = TREE_OPERAND (expr, 1); + expr = build_offset_ref (qualifying_class, expr, + /*address_p=*/true); + return expr; + } + + if (TREE_CODE (expr) == FIELD_DECL) + expr = finish_non_static_data_member (expr, current_class_ref, + qualifying_class); + else if (BASELINK_P (expr) && !processing_template_decl) + { + tree fn; + tree fns; + + /* See if any of the functions are non-static members. */ + fns = BASELINK_FUNCTIONS (expr); + if (TREE_CODE (fns) == TEMPLATE_ID_EXPR) + fns = TREE_OPERAND (fns, 0); + for (fn = fns; fn; fn = OVL_NEXT (fn)) + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) + break; + /* If so, the expression may be relative to the current + class. */ + if (fn && current_class_type + && DERIVED_FROM_P (qualifying_class, current_class_type)) + expr = (build_class_member_access_expr + (maybe_dummy_object (qualifying_class, NULL), + expr, + BASELINK_ACCESS_BINFO (expr), + /*preserve_reference=*/false)); + else if (done) + /* The expression is a qualified name whose address is not + being taken. */ + expr = build_offset_ref (qualifying_class, expr, /*address_p=*/false); + } + + return expr; +} + /* Begin a statement-expression. The value returned must be passed to finish_stmt_expr. */ tree -begin_stmt_expr () +begin_stmt_expr (void) { /* If we're outside a function, we won't have a statement-tree to work with. But, if we see a statement-expression we need to @@ -1154,61 +1428,102 @@ begin_stmt_expr () if (! cfun && !last_tree) begin_stmt_tree (&scope_chain->x_saved_tree); - keep_next_level (1); - /* If we're building a statement tree, then the upcoming compound - statement will be chained onto the tree structure, starting at - last_tree. We return last_tree so that we can later unhook the - compound statement. */ + last_expr_type = NULL_TREE; + + keep_next_level (true); + return last_tree; } -/* Used when beginning a statement-expression outside function scope. - For example, when handling a file-scope initializer, we use this - function. */ +/* Process the final expression of a statement expression. EXPR can be + NULL, if the final expression is empty. Build up a TARGET_EXPR so + that the result value can be safely returned to the enclosing + expression. */ tree -begin_global_stmt_expr () +finish_stmt_expr_expr (tree expr) { - if (! cfun && !last_tree) - begin_stmt_tree (&scope_chain->x_saved_tree); - - keep_next_level (1); - - return last_tree ? last_tree : expand_start_stmt_expr(/*has_scope=*/1); -} + tree result = NULL_TREE; + tree type = void_type_node; -/* Finish the STMT_EXPR last begun with begin_global_stmt_expr. */ + if (expr) + { + type = TREE_TYPE (expr); + + if (!processing_template_decl && !VOID_TYPE_P (TREE_TYPE (expr))) + { + if (TREE_CODE (type) == ARRAY_TYPE + || TREE_CODE (type) == FUNCTION_TYPE) + expr = decay_conversion (expr); + + expr = convert_from_reference (expr); + expr = require_complete_type (expr); + + /* Build a TARGET_EXPR for this aggregate. finish_stmt_expr + will then pull it apart so the lifetime of the target is + within the scope of the expression containing this statement + expression. */ + if (TREE_CODE (expr) == TARGET_EXPR) + ; + else if (!IS_AGGR_TYPE (type) || TYPE_HAS_TRIVIAL_INIT_REF (type)) + expr = build_target_expr_with_type (expr, type); + else + { + /* Copy construct. */ + expr = build_special_member_call + (NULL_TREE, complete_ctor_identifier, + build_tree_list (NULL_TREE, expr), + TYPE_BINFO (type), LOOKUP_NORMAL); + expr = build_cplus_new (type, expr); + my_friendly_assert (TREE_CODE (expr) == TARGET_EXPR, 20030729); + } + } -tree -finish_global_stmt_expr (stmt_expr) - tree stmt_expr; -{ - stmt_expr = expand_end_stmt_expr (stmt_expr); + if (expr != error_mark_node) + { + result = build_stmt (EXPR_STMT, expr); + add_stmt (result); + } + } - if (! cfun - && TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE) - finish_stmt_tree (&scope_chain->x_saved_tree); + finish_stmt (); - return stmt_expr; + /* Remember the last expression so that finish_stmt_expr can pull it + apart. */ + last_expr_type = result ? result : void_type_node; + + return result; } -/* Finish a statement-expression. RTL_EXPR should be the value - returned by the previous begin_stmt_expr; EXPR is the - statement-expression. Returns an expression representing the - statement-expression. */ +/* Finish a statement-expression. EXPR should be the value returned + by the previous begin_stmt_expr. Returns an expression + representing the statement-expression. */ tree -finish_stmt_expr (rtl_expr) - tree rtl_expr; +finish_stmt_expr (tree rtl_expr, bool has_no_scope) { tree result; - - /* If the last thing in the statement-expression was not an - expression-statement, then it has type `void'. */ + tree result_stmt = last_expr_type; + tree type; + if (!last_expr_type) - last_expr_type = void_type_node; - result = build_min (STMT_EXPR, last_expr_type, last_tree); + type = void_type_node; + else + { + if (result_stmt == void_type_node) + { + type = void_type_node; + result_stmt = NULL_TREE; + } + else + type = TREE_TYPE (EXPR_STMT_EXPR (result_stmt)); + } + + result = build_min (STMT_EXPR, type, last_tree); TREE_SIDE_EFFECTS (result) = 1; + STMT_EXPR_NO_SCOPE (result) = has_no_scope; + + last_expr_type = NULL_TREE; /* Remove the compound statement from the tree structure; it is now saved in the STMT_EXPR. */ @@ -1221,9 +1536,67 @@ finish_stmt_expr (rtl_expr) && TREE_CHAIN (scope_chain->x_saved_tree) == NULL_TREE) finish_stmt_tree (&scope_chain->x_saved_tree); + if (processing_template_decl) + return result; + + if (!VOID_TYPE_P (type)) + { + /* Pull out the TARGET_EXPR that is the final expression. Put + the target's init_expr as the final expression and then put + the statement expression itself as the target's init + expr. Finally, return the target expression. */ + tree last_expr = EXPR_STMT_EXPR (result_stmt); + + my_friendly_assert (TREE_CODE (last_expr) == TARGET_EXPR, 20030729); + EXPR_STMT_EXPR (result_stmt) = TREE_OPERAND (last_expr, 1); + TREE_OPERAND (last_expr, 1) = result; + result = last_expr; + } return result; } +/* Perform Koenig lookup. FN is the postfix-expression representing + the function (or functions) to call; ARGS are the arguments to the + call. Returns the functions to be considered by overload + resolution. */ + +tree +perform_koenig_lookup (tree fn, tree args) +{ + tree identifier = NULL_TREE; + tree functions = NULL_TREE; + + /* Find the name of the overloaded function. */ + if (TREE_CODE (fn) == IDENTIFIER_NODE) + identifier = fn; + else if (is_overloaded_fn (fn)) + { + functions = fn; + identifier = DECL_NAME (get_first_fn (functions)); + } + else if (DECL_P (fn)) + { + functions = fn; + identifier = DECL_NAME (fn); + } + + /* A call to a namespace-scope function using an unqualified name. + + Do Koenig lookup -- unless any of the arguments are + type-dependent. */ + if (!any_type_dependent_arguments_p (args)) + { + fn = lookup_arg_dependent (identifier, functions, args); + if (!fn) + /* The unqualified name could not be resolved. */ + fn = unqualified_fn_lookup_error (identifier); + } + else + fn = identifier; + + return fn; +} + /* Generate an expression for `FN (ARGS)'. If DISALLOW_VIRTUAL is true, the call to FN will be not generated @@ -1235,18 +1608,60 @@ finish_stmt_expr (rtl_expr) Returns code for the call. */ tree -finish_call_expr (tree fn, tree args, bool disallow_virtual) +finish_call_expr (tree fn, tree args, bool disallow_virtual, bool koenig_p) { + tree result; + tree orig_fn; + tree orig_args; + if (fn == error_mark_node || args == error_mark_node) return error_mark_node; - if (processing_template_decl) - return build_nt (CALL_EXPR, fn, args, NULL_TREE); - /* ARGS should be a list of arguments. */ my_friendly_assert (!args || TREE_CODE (args) == TREE_LIST, 20020712); + orig_fn = fn; + orig_args = args; + + if (processing_template_decl) + { + if (type_dependent_expression_p (fn) + || any_type_dependent_arguments_p (args)) + { + result = build_nt (CALL_EXPR, fn, args); + KOENIG_LOOKUP_P (result) = koenig_p; + return result; + } + if (!BASELINK_P (fn) + && TREE_CODE (fn) != PSEUDO_DTOR_EXPR + && TREE_TYPE (fn) != unknown_type_node) + fn = build_non_dependent_expr (fn); + args = build_non_dependent_args (orig_args); + } + + /* A reference to a member function will appear as an overloaded + function (rather than a BASELINK) if an unqualified name was used + to refer to it. */ + if (!BASELINK_P (fn) && is_overloaded_fn (fn)) + { + tree f = fn; + + if (TREE_CODE (f) == TEMPLATE_ID_EXPR) + f = TREE_OPERAND (f, 0); + f = get_first_fn (f); + if (DECL_FUNCTION_MEMBER_P (f)) + { + tree type = currently_open_derived_class (DECL_CONTEXT (f)); + if (!type) + type = DECL_CONTEXT (f); + fn = build_baselink (TYPE_BINFO (type), + TYPE_BINFO (type), + fn, /*optype=*/NULL_TREE); + } + } + + result = NULL_TREE; if (BASELINK_P (fn)) { tree object; @@ -1286,25 +1701,46 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual) object = build_dummy_object (DECL_CONTEXT (representative_fn)); } - return build_new_method_call (object, fn, args, NULL_TREE, - (disallow_virtual - ? LOOKUP_NONVIRTUAL : 0)); + if (processing_template_decl) + { + if (type_dependent_expression_p (object)) + return build_nt (CALL_EXPR, orig_fn, orig_args); + object = build_non_dependent_expr (object); + } + + result = build_new_method_call (object, fn, args, NULL_TREE, + (disallow_virtual + ? LOOKUP_NONVIRTUAL : 0)); } else if (is_overloaded_fn (fn)) /* A call to a namespace-scope function. */ - return build_new_function_call (fn, args); - else if (CLASS_TYPE_P (TREE_TYPE (fn))) + result = build_new_function_call (fn, args); + else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR) { - /* If the "function" is really an object of class type, it might - have an overloaded `operator ()'. */ - tree result; - result = build_opfncall (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE); - if (result) - return result; + if (args) + error ("arguments to destructor are not allowed"); + /* Mark the pseudo-destructor call as having side-effects so + that we do not issue warnings about its use. */ + result = build1 (NOP_EXPR, + void_type_node, + TREE_OPERAND (fn, 0)); + TREE_SIDE_EFFECTS (result) = 1; } + else if (CLASS_TYPE_P (TREE_TYPE (fn))) + /* If the "function" is really an object of class type, it might + have an overloaded `operator ()'. */ + result = build_new_op (CALL_EXPR, LOOKUP_NORMAL, fn, args, NULL_TREE, + /*overloaded_p=*/NULL); + if (!result) + /* A call where the function is unknown. */ + result = build_function_call (fn, args); - /* A call where the function is unknown. */ - return build_function_call (fn, args); + if (processing_template_decl) + { + result = build (CALL_EXPR, TREE_TYPE (result), orig_fn, orig_args); + KOENIG_LOOKUP_P (result) = koenig_p; + } + return result; } /* Finish a call to a postfix increment or decrement or EXPR. (Which @@ -1312,24 +1748,15 @@ finish_call_expr (tree fn, tree args, bool disallow_virtual) POSTDECREMENT_EXPR.) */ tree -finish_increment_expr (expr, code) - tree expr; - enum tree_code code; +finish_increment_expr (tree expr, enum tree_code code) { - /* If we get an OFFSET_REF, turn it into what it really means (e.g., - a COMPONENT_REF). This way if we've got, say, a reference to a - static member that's being operated on, we don't end up trying to - find a member operator for the class it's in. */ - - if (TREE_CODE (expr) == OFFSET_REF) - expr = resolve_offset_ref (expr); return build_x_unary_op (code, expr); } /* Finish a use of `this'. Returns an expression for `this'. */ tree -finish_this_expr () +finish_this_expr (void) { tree result; @@ -1355,84 +1782,55 @@ finish_this_expr () return result; } -/* Finish a member function call using OBJECT and ARGS as arguments to - FN. Returns an expression for the call. */ +/* Finish a pseudo-destructor expression. If SCOPE is NULL, the + expression was of the form `OBJECT.~DESTRUCTOR' where DESTRUCTOR is + the TYPE for the type given. If SCOPE is non-NULL, the expression + was of the form `OBJECT.SCOPE::~DESTRUCTOR'. */ tree -finish_object_call_expr (fn, object, args) - tree fn; - tree object; - tree args; +finish_pseudo_destructor_expr (tree object, tree scope, tree destructor) { - if (DECL_DECLARES_TYPE_P (fn)) - { - if (processing_template_decl) - /* This can happen on code like: + if (destructor == error_mark_node) + return error_mark_node; - class X; - template <class T> void f(T t) { - t.X(); - } + my_friendly_assert (TYPE_P (destructor), 20010905); - We just grab the underlying IDENTIFIER. */ - fn = DECL_NAME (fn); - else + if (!processing_template_decl) + { + if (scope == error_mark_node) { - error ("calling type `%T' like a method", fn); + error ("invalid qualifying scope in pseudo-destructor name"); return error_mark_node; } - } - - if (processing_template_decl || name_p (fn)) - return build_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL); - else - return build_new_method_call (object, fn, args, NULL_TREE, LOOKUP_NORMAL); -} - -/* Finish a qualified member function call using OBJECT and ARGS as - arguments to FN. Returns an expression for the call. */ - -tree -finish_qualified_object_call_expr (fn, object, args) - tree fn; - tree object; - tree args; -{ - return build_scoped_method_call (object, TREE_OPERAND (fn, 0), - TREE_OPERAND (fn, 1), args); -} + + /* [expr.pseudo] says both: -/* Finish a pseudo-destructor call expression of OBJECT, with SCOPE - being the scope, if any, of DESTRUCTOR. Returns an expression for - the call. */ + The type designated by the pseudo-destructor-name shall be + the same as the object type. -tree -finish_pseudo_destructor_call_expr (object, scope, destructor) - tree object; - tree scope; - tree destructor; -{ - if (processing_template_decl) - return build_min_nt (PSEUDO_DTOR_EXPR, object, scope, destructor); + and: - if (scope && scope != destructor) - error ("destructor specifier `%T::~%T()' must have matching names", - scope, destructor); + The cv-unqualified versions of the object type and of the + type designated by the pseudo-destructor-name shall be the + same type. - if ((scope == NULL_TREE || IDENTIFIER_GLOBAL_VALUE (destructor)) - && (TREE_CODE (TREE_TYPE (object)) != - TREE_CODE (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (destructor))))) - error ("`%E' is not of type `%T'", object, destructor); + We implement the more generous second sentence, since that is + what most other compilers do. */ + if (!same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (object), + destructor)) + { + error ("`%E' is not of type `%T'", object, destructor); + return error_mark_node; + } + } - return cp_convert (void_type_node, object); + return build (PSEUDO_DTOR_EXPR, void_type_node, object, scope, destructor); } /* Finish an expression of the form CODE EXPR. */ tree -finish_unary_op_expr (code, expr) - enum tree_code code; - tree expr; +finish_unary_op_expr (enum tree_code code, tree expr) { tree result = build_x_unary_op (code, expr); /* Inside a template, build_x_unary_op does not fold the @@ -1447,18 +1845,35 @@ finish_unary_op_expr (code, expr) return result; } -/* Finish an id-expression. */ +/* Finish a compound-literal expression. TYPE is the type to which + the INITIALIZER_LIST is being cast. */ tree -finish_id_expr (expr) - tree expr; +finish_compound_literal (tree type, tree initializer_list) { - if (TREE_CODE (expr) == IDENTIFIER_NODE) - expr = do_identifier (expr, 1, NULL_TREE); + tree compound_literal; - if (TREE_TYPE (expr) == error_mark_node) - expr = error_mark_node; - return expr; + /* Build a CONSTRUCTOR for the INITIALIZER_LIST. */ + compound_literal = build_constructor (NULL_TREE, initializer_list); + /* Mark it as a compound-literal. */ + TREE_HAS_CONSTRUCTOR (compound_literal) = 1; + if (processing_template_decl) + TREE_TYPE (compound_literal) = type; + else + { + /* Check the initialization. */ + compound_literal = digest_init (type, compound_literal, NULL); + /* If the TYPE was an array type with an unknown bound, then we can + figure out the dimension now. For example, something like: + + `(int []) { 2, 3 }' + + implies that the array has two elements. */ + if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type)) + complete_array_type (type, compound_literal, 1); + } + + return compound_literal; } /* Return the declaration for the function-name variable indicated by @@ -1471,83 +1886,20 @@ finish_fname (tree id) decl = fname_decl (C_RID_CODE (id), id); if (processing_template_decl) - decl = build_min_nt (LOOKUP_EXPR, DECL_NAME (decl)); + decl = DECL_NAME (decl); return decl; } -static tree current_type_lookups; - -/* Perform deferred access control for types used in the type of a - declaration. */ - -static void -deferred_type_access_control () -{ - tree lookup = type_lookups; - - if (lookup == error_mark_node) - return; - - for (; lookup; lookup = TREE_CHAIN (lookup)) - enforce_access (TREE_PURPOSE (lookup), TREE_VALUE (lookup)); -} - -void -decl_type_access_control (decl) - tree decl; -{ - tree save_fn; - - if (type_lookups == error_mark_node) - return; - - save_fn = current_function_decl; - - if (decl && TREE_CODE (decl) == FUNCTION_DECL) - current_function_decl = decl; - - deferred_type_access_control (); - - current_function_decl = save_fn; - - /* Now strip away the checks for the current declarator; they were - added to type_lookups after typed_declspecs saved the copy that - ended up in current_type_lookups. */ - type_lookups = current_type_lookups; -} - -void -save_type_access_control (lookups) - tree lookups; -{ - current_type_lookups = lookups; -} - -/* Reset the deferred access control. */ - -void -reset_type_access_control () -{ - type_lookups = NULL_TREE; - current_type_lookups = NULL_TREE; -} - /* Begin a function definition declared with DECL_SPECS, ATTRIBUTES, and DECLARATOR. Returns nonzero if the function-declaration is valid. */ int -begin_function_definition (decl_specs, attributes, declarator) - tree decl_specs; - tree attributes; - tree declarator; +begin_function_definition (tree decl_specs, tree attributes, tree declarator) { if (!start_function (decl_specs, declarator, attributes, SF_DEFAULT)) return 0; - deferred_type_access_control (); - type_lookups = error_mark_node; - /* The things we're about to see are not directly qualified by any template headers we've seen thus far. */ reset_specialization (); @@ -1555,38 +1907,10 @@ begin_function_definition (decl_specs, attributes, declarator) return 1; } -/* Begin a constructor declarator of the form `SCOPE::NAME'. Returns - a SCOPE_REF. */ - -tree -begin_constructor_declarator (scope, name) - tree scope; - tree name; -{ - tree result = build_nt (SCOPE_REF, scope, name); - enter_scope_of (result); - return result; -} - -/* Finish an init-declarator. Returns a DECL. */ - -tree -finish_declarator (declarator, declspecs, attributes, - prefix_attributes, initialized) - tree declarator; - tree declspecs; - tree attributes; - tree prefix_attributes; - int initialized; -{ - return start_decl (declarator, declspecs, initialized, attributes, - prefix_attributes); -} - /* Finish a translation unit. */ void -finish_translation_unit () +finish_translation_unit (void) { /* In case there were missing closebraces, get us back to the global binding level. */ @@ -1596,17 +1920,13 @@ finish_translation_unit () /* Do file scope __FUNCTION__ et al. */ finish_fname_decls (); - - finish_file (); } /* Finish a template type parameter, specified as AGGR IDENTIFIER. Returns the parameter. */ tree -finish_template_type_parm (aggr, identifier) - tree aggr; - tree identifier; +finish_template_type_parm (tree aggr, tree identifier) { if (aggr != class_type_node) { @@ -1621,9 +1941,7 @@ finish_template_type_parm (aggr, identifier) Returns the parameter. */ tree -finish_template_template_parm (aggr, identifier) - tree aggr; - tree identifier; +finish_template_template_parm (tree aggr, tree identifier) { tree decl = build_decl (TYPE_DECL, identifier, NULL_TREE); tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE); @@ -1646,10 +1964,24 @@ check_template_template_default_arg (tree argument) { if (TREE_CODE (argument) != TEMPLATE_DECL && TREE_CODE (argument) != TEMPLATE_TEMPLATE_PARM - && TREE_CODE (argument) != TYPE_DECL && TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE) { - error ("invalid default template argument"); + if (TREE_CODE (argument) == TYPE_DECL) + { + tree t = TREE_TYPE (argument); + + /* Try to emit a slightly smarter error message if we detect + that the user is using a template instantiation. */ + if (CLASSTYPE_TEMPLATE_INFO (t) + && CLASSTYPE_TEMPLATE_INSTANTIATION (t)) + error ("invalid use of type `%T' as a default value for a " + "template template-parameter", t); + else + error ("invalid use of `%D' as a default value for a template " + "template-parameter", argument); + } + else + error ("invalid default argument for a template template parameter"); return error_mark_node; } @@ -1660,9 +1992,7 @@ check_template_template_default_arg (tree argument) nonzero, the parameter list was terminated by a `...'. */ tree -finish_parmlist (parms, ellipsis) - tree parms; - int ellipsis; +finish_parmlist (tree parms, int ellipsis) { if (parms) { @@ -1679,26 +2009,16 @@ finish_parmlist (parms, ellipsis) /* Begin a class definition, as indicated by T. */ tree -begin_class_definition (t) - tree t; +begin_class_definition (tree t) { if (t == error_mark_node) return error_mark_node; - /* Check the bases are accessible. */ - decl_type_access_control (TYPE_NAME (t)); - reset_type_access_control (); - if (processing_template_parmlist) { error ("definition of `%#T' inside template parameter list", t); return error_mark_node; } - - /* In a definition of a member class template, we will get here with - an implicit typename. */ - if (IMPLICIT_TYPENAME_P (t)) - t = TREE_TYPE (t); /* A non-implicit typename comes from code like: template <typename T> struct A { @@ -1717,61 +2037,17 @@ begin_class_definition (t) pushtag (make_anon_name (), t, 0); } - /* If we generated a partial instantiation of this type, but now - we're seeing a real definition, we're actually looking at a - partial specialization. Consider: - - template <class T, class U> - struct Y {}; - - template <class T> - struct X {}; - - template <class T, class U> - void f() - { - typename X<Y<T, U> >::A a; - } - - template <class T, class U> - struct X<Y<T, U> > - { - }; - - We have to undo the effects of the previous partial - instantiation. */ - if (PARTIAL_INSTANTIATION_P (t)) - { - if (!pedantic) - { - /* Unfortunately, when we're not in pedantic mode, we - attempt to actually fill in some of the fields of the - partial instantiation, in order to support the implicit - typename extension. Clear those fields now, in - preparation for the definition here. The fields cleared - here must match those set in instantiate_class_template. - Look for a comment mentioning begin_class_definition - there. */ - TYPE_BINFO_BASETYPES (t) = NULL_TREE; - TYPE_FIELDS (t) = NULL_TREE; - TYPE_METHODS (t) = NULL_TREE; - CLASSTYPE_DECL_LIST (t) = NULL_TREE; - CLASSTYPE_NESTED_UDTS (t) = NULL; - CLASSTYPE_VBASECLASSES (t) = NULL_TREE; - TYPE_SIZE (t) = NULL_TREE; - } - - /* This isn't a partial instantiation any more. */ - PARTIAL_INSTANTIATION_P (t) = 0; - } /* If this type was already complete, and we see another definition, that's an error. */ - else if (COMPLETE_TYPE_P (t)) - duplicate_tag_error (t); + if (COMPLETE_TYPE_P (t)) + { + error ("redefinition of `%#T'", t); + cp_error_at ("previous definition of `%#T'", t); + return error_mark_node; + } /* Update the location of the decl. */ - DECL_SOURCE_FILE (TYPE_NAME (t)) = input_filename; - DECL_SOURCE_LINE (TYPE_NAME (t)) = lineno; + DECL_SOURCE_LOCATION (TYPE_NAME (t)) = input_location; if (TYPE_BEING_DEFINED (t)) { @@ -1779,9 +2055,18 @@ begin_class_definition (t) pushtag (TYPE_IDENTIFIER (t), t, 0); } maybe_process_partial_specialization (t); - pushclass (t, 1); + pushclass (t); TYPE_BEING_DEFINED (t) = 1; - TYPE_PACKED (t) = flag_pack_struct; + if (flag_pack_struct) + { + tree v; + TYPE_PACKED (t) = 1; + /* Even though the type is being defined for the first time + here, there might have been a forward declaration, so there + might be cv-qualified variants of T. */ + for (v = TYPE_NEXT_VARIANT (t); v; v = TYPE_NEXT_VARIANT (v)) + TYPE_PACKED (v) = 1; + } /* Reset the interface data, at the earliest possible moment, as it might have been set via a class foo; before. */ @@ -1802,8 +2087,7 @@ begin_class_definition (t) /* Finish the member declaration given by DECL. */ void -finish_member_declaration (decl) - tree decl; +finish_member_declaration (tree decl) { if (decl == error_mark_node || decl == NULL_TREE) return; @@ -1854,7 +2138,8 @@ finish_member_declaration (decl) /*friend_p=*/0); } /* Enter the DECL into the scope of the class. */ - else if (TREE_CODE (decl) == USING_DECL || pushdecl_class_level (decl)) + else if ((TREE_CODE (decl) == USING_DECL && TREE_TYPE (decl)) + || pushdecl_class_level (decl)) { /* All TYPE_DECLs go at the end of TYPE_FIELDS. Ordinary fields go at the beginning. The reason is that lookup_field_1 @@ -1887,65 +2172,11 @@ finish_member_declaration (decl) } } -/* Finish a class definition T with the indicate ATTRIBUTES. If SEMI, - the definition is immediately followed by a semicolon. Returns the - type. */ - -tree -finish_class_definition (t, attributes, semi, pop_scope_p) - tree t; - tree attributes; - int semi; - int pop_scope_p; -{ - if (t == error_mark_node) - return error_mark_node; - - /* finish_struct nukes this anyway; if finish_exception does too, - then it can go. */ - if (semi) - note_got_semicolon (t); - - /* If we got any attributes in class_head, xref_tag will stick them in - TREE_TYPE of the type. Grab them now. */ - attributes = chainon (TYPE_ATTRIBUTES (t), attributes); - TYPE_ATTRIBUTES (t) = NULL_TREE; - - if (TREE_CODE (t) == ENUMERAL_TYPE) - ; - else - { - t = finish_struct (t, attributes); - if (semi) - note_got_semicolon (t); - } - - if (! semi) - check_for_missing_semicolon (t); - if (pop_scope_p) - pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (t))); - if (current_scope () == current_function_decl) - do_pending_defargs (); - - return t; -} - -/* Finish processing the default argument expressions cached during - the processing of a class definition. */ - -void -begin_inline_definitions () -{ - if (current_scope () == current_function_decl) - do_pending_inlines (); -} - /* Finish processing the declaration of a member class template TYPES whose template parameters are given by PARMS. */ tree -finish_member_class_template (types) - tree types; +finish_member_class_template (tree types) { tree t; @@ -1956,7 +2187,6 @@ finish_member_class_template (types) if (IS_AGGR_TYPE_CODE (TREE_CODE (TREE_VALUE (t)))) maybe_process_partial_specialization (TREE_VALUE (t)); - note_list_got_semicolon (types); grok_x_components (types); if (TYPE_CONTEXT (TREE_VALUE (types)) != current_class_type) /* The component was in fact a friend declaration. We avoid @@ -1976,8 +2206,7 @@ finish_member_class_template (types) the template parameters. */ void -finish_template_decl (parms) - tree parms; +finish_template_decl (tree parms) { if (parms) end_template_decl (); @@ -1991,50 +2220,19 @@ finish_template_decl (parms) the scope of template-id indicated. */ tree -finish_template_type (name, args, entering_scope) - tree name; - tree args; - int entering_scope; +finish_template_type (tree name, tree args, int entering_scope) { tree decl; decl = lookup_template_class (name, args, - NULL_TREE, NULL_TREE, - entering_scope, /*complain=*/1); + NULL_TREE, NULL_TREE, entering_scope, + tf_error | tf_warning | tf_user); if (decl != error_mark_node) decl = TYPE_STUB_DECL (decl); return decl; } -/* SR is a SCOPE_REF node. Enter the scope of SR, whether it is a - namespace scope or a class scope. */ - -void -enter_scope_of (sr) - tree sr; -{ - tree scope = TREE_OPERAND (sr, 0); - - if (TREE_CODE (scope) == NAMESPACE_DECL) - { - push_decl_namespace (scope); - TREE_COMPLEXITY (sr) = -1; - } - else if (scope != current_class_type) - { - if (TREE_CODE (scope) == TYPENAME_TYPE) - { - /* In a declarator for a template class member, the scope will - get here as an implicit typename, a TYPENAME_TYPE with a type. */ - scope = TREE_TYPE (scope); - TREE_OPERAND (sr, 0) = scope; - } - push_nested_class (scope, 3); - TREE_COMPLEXITY (sr) = current_class_depth; - } -} - /* Finish processing a BASE_CLASS with the indicated ACCESS_SPECIFIER. Return a TREE_LIST containing the ACCESS_SPECIFIER and the BASE_CLASS, or NULL_TREE if an error occurred. The @@ -2042,37 +2240,36 @@ enter_scope_of (sr) access_{default,public,protected_private}[_virtual]_node.*/ tree -finish_base_specifier (access_specifier, base_class) - tree access_specifier; - tree base_class; +finish_base_specifier (tree base, tree access, bool virtual_p) { tree result; - if (base_class == error_mark_node) + if (base == error_mark_node) { error ("invalid base-class specification"); result = NULL_TREE; } - else if (! is_aggr_type (base_class, 1)) + else if (! is_aggr_type (base, 1)) result = NULL_TREE; else { - if (cp_type_quals (base_class) != 0) + if (cp_type_quals (base) != 0) { - error ("base class `%T' has cv qualifiers", base_class); - base_class = TYPE_MAIN_VARIANT (base_class); + error ("base class `%T' has cv qualifiers", base); + base = TYPE_MAIN_VARIANT (base); } - result = build_tree_list (access_specifier, base_class); + result = build_tree_list (access, base); + TREE_VIA_VIRTUAL (result) = virtual_p; } return result; } /* Called when multiple declarators are processed. If that is not - premitted in this context, an error is issued. */ + permitted in this context, an error is issued. */ void -check_multiple_declarators () +check_multiple_declarators (void) { /* [temp] @@ -2093,16 +2290,420 @@ check_multiple_declarators () error ("multiple declarators in template declaration"); } +/* Issue a diagnostic that NAME cannot be found in SCOPE. */ + +void +qualified_name_lookup_error (tree scope, tree name) +{ + if (TYPE_P (scope)) + { + if (!COMPLETE_TYPE_P (scope)) + error ("incomplete type `%T' used in nested name specifier", scope); + else + error ("`%D' is not a member of `%T'", name, scope); + } + else if (scope != global_namespace) + error ("`%D' is not a member of `%D'", name, scope); + else + error ("`::%D' has not been declared", name); +} + +/* ID_EXPRESSION is a representation of parsed, but unprocessed, + id-expression. (See cp_parser_id_expression for details.) SCOPE, + if non-NULL, is the type or namespace used to explicitly qualify + ID_EXPRESSION. DECL is the entity to which that name has been + resolved. + + *CONSTANT_EXPRESSION_P is true if we are presently parsing a + constant-expression. In that case, *NON_CONSTANT_EXPRESSION_P will + be set to true if this expression isn't permitted in a + constant-expression, but it is otherwise not set by this function. + *ALLOW_NON_CONSTANT_EXPRESSION_P is true if we are parsing a + constant-expression, but a non-constant expression is also + permissible. + + If an error occurs, and it is the kind of error that might cause + the parser to abort a tentative parse, *ERROR_MSG is filled in. It + is the caller's responsibility to issue the message. *ERROR_MSG + will be a string with static storage duration, so the caller need + not "free" it. + + Return an expression for the entity, after issuing appropriate + diagnostics. This function is also responsible for transforming a + reference to a non-static member into a COMPONENT_REF that makes + the use of "this" explicit. + + Upon return, *IDK will be filled in appropriately. */ + +tree +finish_id_expression (tree id_expression, + tree decl, + tree scope, + cp_id_kind *idk, + tree *qualifying_class, + bool integral_constant_expression_p, + bool allow_non_integral_constant_expression_p, + bool *non_integral_constant_expression_p, + const char **error_msg) +{ + /* Initialize the output parameters. */ + *idk = CP_ID_KIND_NONE; + *error_msg = NULL; + + if (id_expression == error_mark_node) + return error_mark_node; + /* If we have a template-id, then no further lookup is + required. If the template-id was for a template-class, we + will sometimes have a TYPE_DECL at this point. */ + else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR + || TREE_CODE (decl) == TYPE_DECL) + ; + /* Look up the name. */ + else + { + if (decl == error_mark_node) + { + /* Name lookup failed. */ + if (scope + && (!TYPE_P (scope) + || (!dependent_type_p (scope) + && !(TREE_CODE (id_expression) == IDENTIFIER_NODE + && IDENTIFIER_TYPENAME_P (id_expression) + && dependent_type_p (TREE_TYPE (id_expression)))))) + { + /* If the qualifying type is non-dependent (and the name + does not name a conversion operator to a dependent + type), issue an error. */ + qualified_name_lookup_error (scope, id_expression); + return error_mark_node; + } + else if (!scope) + { + /* It may be resolved via Koenig lookup. */ + *idk = CP_ID_KIND_UNQUALIFIED; + return id_expression; + } + else + decl = id_expression; + } + /* If DECL is a variable that would be out of scope under + ANSI/ISO rules, but in scope in the ARM, name lookup + will succeed. Issue a diagnostic here. */ + else + decl = check_for_out_of_scope_variable (decl); + + /* Remember that the name was used in the definition of + the current class so that we can check later to see if + the meaning would have been different after the class + was entirely defined. */ + if (!scope && decl != error_mark_node) + maybe_note_name_used_in_class (id_expression, decl); + } + + /* If we didn't find anything, or what we found was a type, + then this wasn't really an id-expression. */ + if (TREE_CODE (decl) == TEMPLATE_DECL + && !DECL_FUNCTION_TEMPLATE_P (decl)) + { + *error_msg = "missing template arguments"; + return error_mark_node; + } + else if (TREE_CODE (decl) == TYPE_DECL + || TREE_CODE (decl) == NAMESPACE_DECL) + { + *error_msg = "expected primary-expression"; + return error_mark_node; + } + + /* If the name resolved to a template parameter, there is no + need to look it up again later. */ + if ((TREE_CODE (decl) == CONST_DECL && DECL_TEMPLATE_PARM_P (decl)) + || TREE_CODE (decl) == TEMPLATE_PARM_INDEX) + { + *idk = CP_ID_KIND_NONE; + if (TREE_CODE (decl) == TEMPLATE_PARM_INDEX) + decl = TEMPLATE_PARM_DECL (decl); + if (integral_constant_expression_p + && !dependent_type_p (TREE_TYPE (decl)) + && !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl))) + { + if (!allow_non_integral_constant_expression_p) + error ("template parameter `%D' of type `%T' is not allowed in " + "an integral constant expression because it is not of " + "integral or enumeration type", decl, TREE_TYPE (decl)); + *non_integral_constant_expression_p = true; + } + return DECL_INITIAL (decl); + } + /* Similarly, we resolve enumeration constants to their + underlying values. */ + else if (TREE_CODE (decl) == CONST_DECL) + { + *idk = CP_ID_KIND_NONE; + if (!processing_template_decl) + return DECL_INITIAL (decl); + return decl; + } + else + { + bool dependent_p; + + /* If the declaration was explicitly qualified indicate + that. The semantics of `A::f(3)' are different than + `f(3)' if `f' is virtual. */ + *idk = (scope + ? CP_ID_KIND_QUALIFIED + : (TREE_CODE (decl) == TEMPLATE_ID_EXPR + ? CP_ID_KIND_TEMPLATE_ID + : CP_ID_KIND_UNQUALIFIED)); + + + /* [temp.dep.expr] + + An id-expression is type-dependent if it contains an + identifier that was declared with a dependent type. + + The standard is not very specific about an id-expression that + names a set of overloaded functions. What if some of them + have dependent types and some of them do not? Presumably, + such a name should be treated as a dependent name. */ + /* Assume the name is not dependent. */ + dependent_p = false; + if (!processing_template_decl) + /* No names are dependent outside a template. */ + ; + /* A template-id where the name of the template was not resolved + is definitely dependent. */ + else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR + && (TREE_CODE (TREE_OPERAND (decl, 0)) + == IDENTIFIER_NODE)) + dependent_p = true; + /* For anything except an overloaded function, just check its + type. */ + else if (!is_overloaded_fn (decl)) + dependent_p + = dependent_type_p (TREE_TYPE (decl)); + /* For a set of overloaded functions, check each of the + functions. */ + else + { + tree fns = decl; + + if (BASELINK_P (fns)) + fns = BASELINK_FUNCTIONS (fns); + + /* For a template-id, check to see if the template + arguments are dependent. */ + if (TREE_CODE (fns) == TEMPLATE_ID_EXPR) + { + tree args = TREE_OPERAND (fns, 1); + dependent_p = any_dependent_template_arguments_p (args); + /* The functions are those referred to by the + template-id. */ + fns = TREE_OPERAND (fns, 0); + } + + /* If there are no dependent template arguments, go through + the overloaded functions. */ + while (fns && !dependent_p) + { + tree fn = OVL_CURRENT (fns); + + /* Member functions of dependent classes are + dependent. */ + if (TREE_CODE (fn) == FUNCTION_DECL + && type_dependent_expression_p (fn)) + dependent_p = true; + else if (TREE_CODE (fn) == TEMPLATE_DECL + && dependent_template_p (fn)) + dependent_p = true; + + fns = OVL_NEXT (fns); + } + } + + /* If the name was dependent on a template parameter, we will + resolve the name at instantiation time. */ + if (dependent_p) + { + /* Create a SCOPE_REF for qualified names, if the scope is + dependent. */ + if (scope) + { + if (TYPE_P (scope)) + *qualifying_class = scope; + /* Since this name was dependent, the expression isn't + constant -- yet. No error is issued because it might + be constant when things are instantiated. */ + if (integral_constant_expression_p) + *non_integral_constant_expression_p = true; + if (TYPE_P (scope) && dependent_type_p (scope)) + return build_nt (SCOPE_REF, scope, id_expression); + else if (TYPE_P (scope) && DECL_P (decl)) + return build (SCOPE_REF, TREE_TYPE (decl), scope, + id_expression); + else + return decl; + } + /* A TEMPLATE_ID already contains all the information we + need. */ + if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR) + return id_expression; + /* Since this name was dependent, the expression isn't + constant -- yet. No error is issued because it might be + constant when things are instantiated. */ + if (integral_constant_expression_p) + *non_integral_constant_expression_p = true; + *idk = CP_ID_KIND_UNQUALIFIED_DEPENDENT; + /* If we found a variable, then name lookup during the + instantiation will always resolve to the same VAR_DECL + (or an instantiation thereof). */ + if (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL) + return decl; + return id_expression; + } + + /* Only certain kinds of names are allowed in constant + expression. Enumerators and template parameters + have already been handled above. */ + if (integral_constant_expression_p) + { + /* Const variables or static data members of integral or + enumeration types initialized with constant expressions + are OK. */ + if (TREE_CODE (decl) == VAR_DECL + && CP_TYPE_CONST_P (TREE_TYPE (decl)) + && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (decl)) + && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)) + ; + else + { + if (!allow_non_integral_constant_expression_p) + { + error ("`%D' cannot appear in a constant-expression", decl); + return error_mark_node; + } + *non_integral_constant_expression_p = true; + } + } + + if (TREE_CODE (decl) == NAMESPACE_DECL) + { + error ("use of namespace `%D' as expression", decl); + return error_mark_node; + } + else if (DECL_CLASS_TEMPLATE_P (decl)) + { + error ("use of class template `%T' as expression", decl); + return error_mark_node; + } + else if (TREE_CODE (decl) == TREE_LIST) + { + /* Ambiguous reference to base members. */ + error ("request for member `%D' is ambiguous in " + "multiple inheritance lattice", id_expression); + print_candidates (decl); + return error_mark_node; + } + + /* Mark variable-like entities as used. Functions are similarly + marked either below or after overload resolution. */ + if (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == RESULT_DECL) + mark_used (decl); + + if (scope) + { + decl = (adjust_result_of_qualified_name_lookup + (decl, scope, current_class_type)); + + if (TREE_CODE (decl) == FUNCTION_DECL) + mark_used (decl); + + if (TREE_CODE (decl) == FIELD_DECL || BASELINK_P (decl)) + *qualifying_class = scope; + else if (!processing_template_decl) + decl = convert_from_reference (decl); + else if (TYPE_P (scope)) + decl = build (SCOPE_REF, TREE_TYPE (decl), scope, decl); + } + else if (TREE_CODE (decl) == FIELD_DECL) + decl = finish_non_static_data_member (decl, current_class_ref, + /*qualifying_scope=*/NULL_TREE); + else if (is_overloaded_fn (decl)) + { + tree first_fn = OVL_CURRENT (decl); + + if (TREE_CODE (first_fn) == TEMPLATE_DECL) + first_fn = DECL_TEMPLATE_RESULT (first_fn); + + if (!really_overloaded_fn (decl)) + mark_used (first_fn); + + if (TREE_CODE (first_fn) == FUNCTION_DECL + && DECL_FUNCTION_MEMBER_P (first_fn)) + { + /* A set of member functions. */ + decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0); + return finish_class_member_access_expr (decl, id_expression); + } + } + else + { + if (TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL + || TREE_CODE (decl) == RESULT_DECL) + { + tree context = decl_function_context (decl); + + if (context != NULL_TREE && context != current_function_decl + && ! TREE_STATIC (decl)) + { + error ("use of %s from containing function", + (TREE_CODE (decl) == VAR_DECL + ? "`auto' variable" : "parameter")); + cp_error_at (" `%#D' declared here", decl); + return error_mark_node; + } + } + + if (DECL_P (decl) && DECL_NONLOCAL (decl) + && DECL_CLASS_SCOPE_P (decl) + && DECL_CONTEXT (decl) != current_class_type) + { + tree path; + + path = currently_open_derived_class (DECL_CONTEXT (decl)); + perform_or_defer_access_check (TYPE_BINFO (path), decl); + } + + if (! processing_template_decl) + decl = convert_from_reference (decl); + } + + /* Resolve references to variables of anonymous unions + into COMPONENT_REFs. */ + if (TREE_CODE (decl) == ALIAS_DECL) + decl = DECL_INITIAL (decl); + } + + if (TREE_DEPRECATED (decl)) + warn_deprecated_use (decl); + + return decl; +} + /* Implement the __typeof keyword: Return the type of EXPR, suitable for use as a type-specifier. */ tree -finish_typeof (expr) - tree expr; +finish_typeof (tree expr) { tree type; - if (processing_template_decl) + if (type_dependent_expression_p (expr)) { type = make_aggr_type (TYPEOF_TYPE); TYPE_FIELDS (type) = expr; @@ -2110,9 +2711,6 @@ finish_typeof (expr) return type; } - if (TREE_CODE (expr) == OFFSET_REF) - expr = resolve_offset_ref (expr); - type = TREE_TYPE (expr); if (!type || type == unknown_type_node) @@ -2124,37 +2722,11 @@ finish_typeof (expr) return type; } -/* Compute the value of the `sizeof' operator. */ - -tree -finish_sizeof (t) - tree t; -{ - if (processing_template_decl) - return build_min_nt (SIZEOF_EXPR, t); - - return TYPE_P (t) ? cxx_sizeof (t) : expr_sizeof (t); -} - -/* Implement the __alignof keyword: Return the minimum required - alignment of T, measured in bytes. */ - -tree -finish_alignof (t) - tree t; -{ - if (processing_template_decl) - return build_min_nt (ALIGNOF_EXPR, t); - - return TYPE_P (t) ? cxx_alignof (t) : c_alignof_expr (t); -} - /* Generate RTL for the statement T, and its substatements, and any other statements at its nesting level. */ static void -cp_expand_stmt (t) - tree t; +cp_expand_stmt (tree t) { switch (TREE_CODE (t)) { @@ -2170,10 +2742,6 @@ cp_expand_stmt (t) genrtl_handler (t); break; - case RETURN_INIT: - genrtl_named_return_value (); - break; - case USING_STMT: break; @@ -2187,95 +2755,120 @@ cp_expand_stmt (t) will equivalent CALL_EXPRs. */ static tree -simplify_aggr_init_exprs_r (tp, walk_subtrees, data) - tree *tp; - int *walk_subtrees ATTRIBUTE_UNUSED; - void *data ATTRIBUTE_UNUSED; +simplify_aggr_init_exprs_r (tree* tp, + int* walk_subtrees, + void* data ATTRIBUTE_UNUSED) { - tree aggr_init_expr; - tree call_expr; - tree fn; - tree args; - tree slot; - tree type; - int copy_from_buffer_p; - - aggr_init_expr = *tp; /* We don't need to walk into types; there's nothing in a type that needs simplification. (And, furthermore, there are places we actively don't want to go. For example, we don't want to wander into the default arguments for a FUNCTION_DECL that appears in a CALL_EXPR.) */ - if (TYPE_P (aggr_init_expr)) + if (TYPE_P (*tp)) { *walk_subtrees = 0; return NULL_TREE; } /* Only AGGR_INIT_EXPRs are interesting. */ - else if (TREE_CODE (aggr_init_expr) != AGGR_INIT_EXPR) + else if (TREE_CODE (*tp) != AGGR_INIT_EXPR) return NULL_TREE; + simplify_aggr_init_expr (tp); + + /* Keep iterating. */ + return NULL_TREE; +} + +/* Replace the AGGR_INIT_EXPR at *TP with an equivalent CALL_EXPR. This + function is broken out from the above for the benefit of the tree-ssa + project. */ + +void +simplify_aggr_init_expr (tree *tp) +{ + tree aggr_init_expr = *tp; + /* Form an appropriate CALL_EXPR. */ - fn = TREE_OPERAND (aggr_init_expr, 0); - args = TREE_OPERAND (aggr_init_expr, 1); - slot = TREE_OPERAND (aggr_init_expr, 2); - type = TREE_TYPE (aggr_init_expr); + tree fn = TREE_OPERAND (aggr_init_expr, 0); + tree args = TREE_OPERAND (aggr_init_expr, 1); + tree slot = TREE_OPERAND (aggr_init_expr, 2); + tree type = TREE_TYPE (aggr_init_expr); + + tree call_expr; + enum style_t { ctor, arg, pcc } style; + if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr)) + style = ctor; +#ifdef PCC_STATIC_STRUCT_RETURN + else if (1) + style = pcc; +#endif + else if (TREE_ADDRESSABLE (type)) + style = arg; + else + /* We shouldn't build an AGGR_INIT_EXPR if we don't need any special + handling. See build_cplus_new. */ + abort (); + + if (style == ctor || style == arg) { - /* Replace the first argument with the address of the third - argument to the AGGR_INIT_EXPR. */ + /* Pass the address of the slot. If this is a constructor, we + replace the first argument; otherwise, we tack on a new one. */ + tree addr; + + if (style == ctor) + args = TREE_CHAIN (args); + cxx_mark_addressable (slot); - args = tree_cons (NULL_TREE, - build1 (ADDR_EXPR, - build_pointer_type (TREE_TYPE (slot)), - slot), - TREE_CHAIN (args)); + addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (slot)), slot); + if (style == arg) + { + /* The return type might have different cv-quals from the slot. */ + tree fntype = TREE_TYPE (TREE_TYPE (fn)); +#ifdef ENABLE_CHECKING + if (TREE_CODE (fntype) != FUNCTION_TYPE + && TREE_CODE (fntype) != METHOD_TYPE) + abort (); +#endif + addr = convert (build_pointer_type (TREE_TYPE (fntype)), addr); + } + + args = tree_cons (NULL_TREE, addr, args); } + call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), fn, args, NULL_TREE); - TREE_SIDE_EFFECTS (call_expr) = 1; - /* If we're using the non-reentrant PCC calling convention, then we - need to copy the returned value out of the static buffer into the - SLOT. */ - copy_from_buffer_p = 0; -#ifdef PCC_STATIC_STRUCT_RETURN - if (!AGGR_INIT_VIA_CTOR_P (aggr_init_expr) && aggregate_value_p (type)) + if (style == arg) + /* Tell the backend that we've added our return slot to the argument + list. */ + CALL_EXPR_HAS_RETURN_SLOT_ADDR (call_expr) = 1; + else if (style == pcc) { - int old_ac = flag_access_control; - - flag_access_control = 0; + /* If we're using the non-reentrant PCC calling convention, then we + need to copy the returned value out of the static buffer into the + SLOT. */ + push_deferring_access_checks (dk_no_check); call_expr = build_aggr_init (slot, call_expr, DIRECT_BIND | LOOKUP_ONLYCONVERTING); - flag_access_control = old_ac; - copy_from_buffer_p = 1; + pop_deferring_access_checks (); } -#endif - /* If this AGGR_INIT_EXPR indicates the value returned by a - function, then we want to use the value of the initialized - location as the result. */ - if (AGGR_INIT_VIA_CTOR_P (aggr_init_expr) || copy_from_buffer_p) - { - call_expr = build (COMPOUND_EXPR, type, - call_expr, slot); - TREE_SIDE_EFFECTS (call_expr) = 1; - } + /* We want to use the value of the initialized location as the + result. */ + call_expr = build (COMPOUND_EXPR, type, + call_expr, slot); /* Replace the AGGR_INIT_EXPR with the CALL_EXPR. */ TREE_CHAIN (call_expr) = TREE_CHAIN (aggr_init_expr); *tp = call_expr; - - /* Keep iterating. */ - return NULL_TREE; } /* Emit all thunks to FN that should be emitted when FN is emitted. */ static void -emit_associated_thunks (fn) - tree fn; +emit_associated_thunks (tree fn) { /* When we use vcall offsets, we emit thunks with the virtual functions to which they thunk. The whole point of vcall offsets @@ -2285,30 +2878,104 @@ emit_associated_thunks (fn) if (DECL_VIRTUAL_P (fn)) { tree thunk; + for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk)) - use_thunk (thunk, /*emit_p=*/1); + { + if (!THUNK_ALIAS (thunk)) + { + use_thunk (thunk, /*emit_p=*/1); + if (DECL_RESULT_THUNK_P (thunk)) + { + tree probe; + + for (probe = DECL_THUNKS (thunk); + probe; probe = TREE_CHAIN (probe)) + use_thunk (probe, /*emit_p=*/1); + } + } + else + my_friendly_assert (!DECL_THUNKS (thunk), 20031023); + } } } /* Generate RTL for FN. */ void -expand_body (fn) - tree fn; +expand_body (tree fn) { - int saved_lineno; - const char *saved_input_filename; tree saved_function; + + /* Compute the appropriate object-file linkage for inline + functions. */ + if (DECL_DECLARED_INLINE_P (fn)) + import_export_decl (fn); + + /* If FN is external, then there's no point in generating RTL for + it. This situation can arise with an inline function under + `-fexternal-templates'; we instantiate the function, even though + we're not planning on emitting it, in case we get a chance to + inline it. */ + if (DECL_EXTERNAL (fn)) + return; + + /* ??? When is this needed? */ + saved_function = current_function_decl; + + /* Emit any thunks that should be emitted at the same time as FN. */ + emit_associated_thunks (fn); + + timevar_push (TV_INTEGRATION); + optimize_function (fn); + timevar_pop (TV_INTEGRATION); + + tree_rest_of_compilation (fn, function_depth > 1); + + current_function_decl = saved_function; + + extract_interface_info (); + /* If this function is marked with the constructor attribute, add it + to the list of functions to be called along with constructors + from static duration objects. */ + if (DECL_STATIC_CONSTRUCTOR (fn)) + static_ctors = tree_cons (NULL_TREE, fn, static_ctors); + + /* If this function is marked with the destructor attribute, add it + to the list of functions to be called along with destructors from + static duration objects. */ + if (DECL_STATIC_DESTRUCTOR (fn)) + static_dtors = tree_cons (NULL_TREE, fn, static_dtors); + + if (DECL_CLONED_FUNCTION_P (fn)) + { + /* If this is a clone, go through the other clones now and mark + their parameters used. We have to do that here, as we don't + know whether any particular clone will be expanded, and + therefore cannot pick one arbitrarily. */ + tree probe; + + for (probe = TREE_CHAIN (DECL_CLONED_FUNCTION (fn)); + probe && DECL_CLONED_FUNCTION_P (probe); + probe = TREE_CHAIN (probe)) + { + tree parms; + + for (parms = DECL_ARGUMENTS (probe); + parms; parms = TREE_CHAIN (parms)) + TREE_USED (parms) = 1; + } + } +} + +/* Generate RTL for FN. */ + +void +expand_or_defer_fn (tree fn) +{ /* When the parser calls us after finishing the body of a template - function, we don't really want to expand the body. When we're - processing an in-class definition of an inline function, - PROCESSING_TEMPLATE_DECL will no longer be set here, so we have - to look at the function itself. */ - if (processing_template_decl - || (DECL_LANG_SPECIFIC (fn) - && DECL_TEMPLATE_INFO (fn) - && uses_template_parms (DECL_TI_ARGS (fn)))) + function, we don't really want to expand the body. */ + if (processing_template_decl) { /* Normally, collection only occurs in rest_of_compilation. So, if we don't collect here, we never collect junk generated @@ -2338,102 +3005,16 @@ expand_body (fn) if (flag_syntax_only) return; - /* If possible, avoid generating RTL for this function. Instead, - just record it as an inline function, and wait until end-of-file - to decide whether to write it out or not. */ - if (/* We have to generate RTL if it's not an inline function. */ - (DECL_INLINE (fn) || DECL_COMDAT (fn)) - /* Or if we have to emit code for inline functions anyhow. */ - && !flag_keep_inline_functions - /* Or if we actually have a reference to the function. */ - && !DECL_NEEDED_P (fn)) - { - /* Set DECL_EXTERNAL so that assemble_external will be called as - necessary. We'll clear it again in finish_file. */ - if (!DECL_EXTERNAL (fn)) - { - DECL_NOT_REALLY_EXTERN (fn) = 1; - DECL_EXTERNAL (fn) = 1; - } - /* Remember this function. In finish_file we'll decide if - we actually need to write this function out. */ - defer_fn (fn); - /* Let the back-end know that this function exists. */ - (*debug_hooks->deferred_inline_function) (fn); - return; - } - - /* Compute the appropriate object-file linkage for inline - functions. */ + /* Compute the appropriate object-file linkage for inline functions. */ if (DECL_DECLARED_INLINE_P (fn)) import_export_decl (fn); - /* If FN is external, then there's no point in generating RTL for - it. This situation can arise with an inline function under - `-fexternal-templates'; we instantiate the function, even though - we're not planning on emitting it, in case we get a chance to - inline it. */ - if (DECL_EXTERNAL (fn)) - return; - - /* Save the current file name and line number. When we expand the - body of the function, we'll set LINENO and INPUT_FILENAME so that - error-mesages come out in the right places. */ - saved_lineno = lineno; - saved_input_filename = input_filename; - saved_function = current_function_decl; - lineno = DECL_SOURCE_LINE (fn); - input_filename = DECL_SOURCE_FILE (fn); - current_function_decl = fn; + function_depth++; - timevar_push (TV_INTEGRATION); - - /* Optimize the body of the function before expanding it. */ - optimize_function (fn); - - timevar_pop (TV_INTEGRATION); - timevar_push (TV_EXPAND); + /* Expand or defer, at the whim of the compilation unit manager. */ + cgraph_finalize_function (fn, function_depth > 1); - genrtl_start_function (fn); - current_function_is_thunk = DECL_THUNK_P (fn); - - /* Expand the body. */ - expand_stmt (DECL_SAVED_TREE (fn)); - - /* Statements should always be full-expressions at the outermost set - of curly braces for a function. */ - my_friendly_assert (stmts_are_full_exprs_p (), 19990831); - - /* The outermost statement for a function contains the line number - recorded when we finished processing the function. */ - lineno = STMT_LINENO (DECL_SAVED_TREE (fn)); - - /* Generate code for the function. */ - genrtl_finish_function (fn); - - /* If possible, obliterate the body of the function so that it can - be garbage collected. */ - if (dump_enabled_p (TDI_all)) - /* Keep the body; we're going to dump it. */ - ; - else if (DECL_INLINE (fn) && flag_inline_trees) - /* We might need the body of this function so that we can expand - it inline somewhere else. */ - ; - else - /* We don't need the body; blow it away. */ - DECL_SAVED_TREE (fn) = NULL_TREE; - - /* And restore the current source position. */ - current_function_decl = saved_function; - lineno = saved_lineno; - input_filename = saved_input_filename; - extract_interface_info (); - - timevar_pop (TV_EXPAND); - - /* Emit any thunks that should be emitted at the same time as FN. */ - emit_associated_thunks (fn); + function_depth--; } /* Helper function for walk_tree, used by finish_function to override all @@ -2441,10 +3022,7 @@ expand_body (fn) value optimization. */ tree -nullify_returns_r (tp, walk_subtrees, data) - tree *tp; - int *walk_subtrees; - void *data; +nullify_returns_r (tree* tp, int* walk_subtrees, void* data) { tree nrv = (tree) data; @@ -2464,206 +3042,20 @@ nullify_returns_r (tp, walk_subtrees, data) /* Start generating the RTL for FN. */ -static void -genrtl_start_function (fn) - tree fn; -{ - /* Tell everybody what function we're processing. */ - current_function_decl = fn; - /* Get the RTL machinery going for this function. */ - init_function_start (fn, DECL_SOURCE_FILE (fn), DECL_SOURCE_LINE (fn)); - /* Let everybody know that we're expanding this function, not doing - semantic analysis. */ - expanding_p = 1; - - /* 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. */ - immediate_size_expand = 0; - cfun->x_dont_save_pending_sizes_p = 1; - - /* Let the user know we're compiling this function. */ - announce_function (fn); - - /* Initialize the per-function data. */ - my_friendly_assert (!DECL_PENDING_INLINE_P (fn), 20000911); - if (DECL_SAVED_FUNCTION_DATA (fn)) - { - /* If we already parsed this function, and we're just expanding it - now, restore saved state. */ - *cp_function_chain = *DECL_SAVED_FUNCTION_DATA (fn); - - /* This function is being processed in whole-function mode; we - already did semantic analysis. */ - cfun->x_whole_function_mode_p = 1; - - /* If we decided that we didn't want to inline this function, - make sure the back-end knows that. */ - if (!current_function_cannot_inline) - current_function_cannot_inline = cp_function_chain->cannot_inline; - - /* We don't need the saved data anymore. Unless this is an inline - function; we need the named return value info for - cp_copy_res_decl_for_inlining. */ - if (! DECL_INLINE (fn)) - DECL_SAVED_FUNCTION_DATA (fn) = NULL; - } - - /* Keep track of how many functions we're presently expanding. */ - ++function_depth; - - /* Create a binding level for the parameters. */ - expand_function_start (fn, /*parms_have_cleanups=*/0); - /* If this function is `main'. */ - if (DECL_MAIN_P (fn)) - expand_main_function (); - +void +cxx_expand_function_start (void) +{ /* Give our named return value the same RTL as our RESULT_DECL. */ if (current_function_return_value) - COPY_DECL_RTL (DECL_RESULT (fn), current_function_return_value); -} - -/* Finish generating the RTL for FN. */ - -static void -genrtl_finish_function (fn) - tree fn; -{ - tree t; - -#if 0 - if (write_symbols != NO_DEBUG) - { - /* Keep this code around in case we later want to control debug info - based on whether a type is "used". (jason 1999-11-11) */ - - tree ttype = target_type (fntype); - tree parmdecl; - - if (IS_AGGR_TYPE (ttype)) - /* Let debugger know it should output info for this type. */ - note_debug_info_needed (ttype); - - for (parmdecl = DECL_ARGUMENTS (fndecl); parmdecl; parmdecl = TREE_CHAIN (parmdecl)) - { - ttype = target_type (TREE_TYPE (parmdecl)); - if (IS_AGGR_TYPE (ttype)) - /* Let debugger know it should output info for this type. */ - note_debug_info_needed (ttype); - } - } -#endif - - /* Clean house because we will need to reorder insns here. */ - do_pending_stack_adjust (); - - /* If we have a named return value, we need to force a return so that - the return register is USEd. */ - if (DECL_NAME (DECL_RESULT (fn))) - emit_jump (return_label); - - /* We hard-wired immediate_size_expand to zero in start_function. - Expand_function_end will decrement this variable. So, we set the - variable to one here, so that after the decrement it will remain - zero. */ - immediate_size_expand = 1; - - /* Generate rtl for function exit. */ - expand_function_end (input_filename, lineno, 0); - - /* If this is a nested function (like a template instantiation that - we're compiling in the midst of compiling something else), push a - new GC context. That will keep local variables on the stack from - being collected while we're doing the compilation of this - function. */ - if (function_depth > 1) - ggc_push_context (); - - /* There's no need to defer outputting this function any more; we - know we want to output it. */ - DECL_DEFER_OUTPUT (fn) = 0; - - /* Run the optimizers and output the assembler code for this - function. */ - rest_of_compilation (fn); - - /* Undo the call to ggc_push_context above. */ - if (function_depth > 1) - ggc_pop_context (); - -#if 0 - /* Keep this code around in case we later want to control debug info - based on whether a type is "used". (jason 1999-11-11) */ - - if (ctype && TREE_ASM_WRITTEN (fn)) - note_debug_info_needed (ctype); -#endif - - /* If this function is marked with the constructor attribute, add it - to the list of functions to be called along with constructors - from static duration objects. */ - if (DECL_STATIC_CONSTRUCTOR (fn)) - static_ctors = tree_cons (NULL_TREE, fn, static_ctors); - - /* If this function is marked with the destructor attribute, add it - to the list of functions to be called along with destructors from - static duration objects. */ - if (DECL_STATIC_DESTRUCTOR (fn)) - static_dtors = tree_cons (NULL_TREE, fn, static_dtors); - - --function_depth; - - /* In C++, we should never be saving RTL for the function. */ - my_friendly_assert (!DECL_SAVED_INSNS (fn), 20010903); - - /* Since we don't need the RTL for this function anymore, stop - pointing to it. That's especially important for LABEL_DECLs, - since you can reach all the instructions in the function from the - CODE_LABEL stored in the DECL_RTL for the LABEL_DECL. Walk the - BLOCK-tree, clearing DECL_RTL for LABEL_DECLs and non-static - local variables. */ - walk_tree_without_duplicates (&DECL_SAVED_TREE (fn), - clear_decl_rtl, - NULL); - - /* Clear out the RTL for the arguments. */ - for (t = DECL_ARGUMENTS (fn); t; t = TREE_CHAIN (t)) - { - SET_DECL_RTL (t, NULL_RTX); - DECL_INCOMING_RTL (t) = NULL_RTX; - } - - if (!(flag_inline_trees && DECL_INLINE (fn))) - /* DECL_INITIAL must remain nonzero so we know this was an - actual function definition. */ - DECL_INITIAL (fn) = error_mark_node; - - /* Let the error reporting routines know that we're outside a - function. For a nested function, this value is used in - pop_cp_function_context and then reset via pop_function_context. */ - current_function_decl = NULL_TREE; -} - -/* Clear out the DECL_RTL for the non-static variables in BLOCK and - its sub-blocks. */ - -static tree -clear_decl_rtl (tp, walk_subtrees, data) - tree *tp; - int *walk_subtrees ATTRIBUTE_UNUSED; - void *data ATTRIBUTE_UNUSED; -{ - if (nonstatic_local_decl_p (*tp)) - SET_DECL_RTL (*tp, NULL_RTX); - - return NULL_TREE; + COPY_DECL_RTL (DECL_RESULT (cfun->decl), current_function_return_value); } /* Perform initialization related to this module. */ void -init_cp_semantics () +init_cp_semantics (void) { lang_expand_stmt = cp_expand_stmt; } + +#include "gt-cp-semantics.h" |