diff options
author | peter <peter@FreeBSD.org> | 2008-06-01 00:03:21 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 2008-06-01 00:03:21 +0000 |
commit | a2be5f0c15218b0177d73b17d9bcb7589965d685 (patch) | |
tree | c9f0cd9c22378356a1716d32e13e70bc90f98b9c /gcc/cp/semantics.c | |
parent | 9e0f3cc19c9df1594c9cc36cfd8fddc83c52ad12 (diff) | |
download | FreeBSD-src-a2be5f0c15218b0177d73b17d9bcb7589965d685.zip FreeBSD-src-a2be5f0c15218b0177d73b17d9bcb7589965d685.tar.gz |
Reorganize the gcc vendor import work area. This flattens out a bunch
of unnecessary path components that are relics of cvs2svn.
(These are directory moves)
Diffstat (limited to 'gcc/cp/semantics.c')
-rw-r--r-- | gcc/cp/semantics.c | 3943 |
1 files changed, 3943 insertions, 0 deletions
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c new file mode 100644 index 0000000..8ad1978 --- /dev/null +++ b/gcc/cp/semantics.c @@ -0,0 +1,3943 @@ +/* Perform the semantic phase of parsing, i.e., the process of + building tree structure, checking semantic consistency, and + building RTL. These routines are used both during actual parsing + and during the instantiation of template functions. + + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + 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 GCC. + + 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. + + 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 GCC; see the file COPYING. If not, write to the Free + Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "cp-tree.h" +#include "c-common.h" +#include "tree-inline.h" +#include "tree-mudflap.h" +#include "except.h" +#include "toplev.h" +#include "flags.h" +#include "rtl.h" +#include "expr.h" +#include "output.h" +#include "timevar.h" +#include "debug.h" +#include "diagnostic.h" +#include "cgraph.h" +#include "tree-iterator.h" +#include "vec.h" +#include "target.h" + +/* There routines provide a modular interface to perform many parsing + operations. They may therefore be used during actual parsing, or + during template instantiation, which may be regarded as a + degenerate form of parsing. */ + +static tree maybe_convert_cond (tree); +static tree simplify_aggr_init_exprs_r (tree *, int *, void *); +static void emit_associated_thunks (tree); +static tree finalize_nrv_r (tree *, int *, void *); + + +/* 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 VEC 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 VEC. `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'. */ + +typedef struct deferred_access GTY(()) +{ + /* A VEC representing name-lookups for which we have deferred + checking access controls. We cannot check the accessibility of + names used in a decl-specifier-seq until we know what is being + declared because code like: + + class A { + class B {}; + B* f(); + } + + A::B* A::f() { return 0; } + + is valid, even though `A::B' is not generally accessible. */ + VEC (deferred_access_check,gc)* GTY(()) deferred_access_checks; + + /* The current mode of access checks. */ + enum deferring_kind deferring_access_checks_kind; + +} deferred_access; +DEF_VEC_O (deferred_access); +DEF_VEC_ALLOC_O (deferred_access,gc); + +/* Data for deferred access checking. */ +static GTY(()) VEC(deferred_access,gc) *deferred_access_stack; +static GTY(()) unsigned deferred_access_no_check; + +/* Save the current deferred access states and start deferred + access checking iff DEFER_P is true. */ + +void +push_deferring_access_checks (deferring_kind deferring) +{ + /* For context like template instantiation, access checking + disabling applies to all nested context. */ + if (deferred_access_no_check || deferring == dk_no_check) + deferred_access_no_check++; + else + { + deferred_access *ptr; + + ptr = VEC_safe_push (deferred_access, gc, deferred_access_stack, NULL); + ptr->deferred_access_checks = NULL; + ptr->deferring_access_checks_kind = deferring; + } +} + +/* Resume deferring access checks again after we stopped doing + this previously. */ + +void +resume_deferring_access_checks (void) +{ + if (!deferred_access_no_check) + VEC_last (deferred_access, deferred_access_stack) + ->deferring_access_checks_kind = dk_deferred; +} + +/* Stop deferring access checks. */ + +void +stop_deferring_access_checks (void) +{ + if (!deferred_access_no_check) + VEC_last (deferred_access, 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) +{ + if (deferred_access_no_check) + deferred_access_no_check--; + else + VEC_pop (deferred_access, deferred_access_stack); +} + +/* 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. + */ + +VEC (deferred_access_check,gc)* +get_deferred_access_checks (void) +{ + if (deferred_access_no_check) + return NULL; + else + return (VEC_last (deferred_access, 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) +{ + if (deferred_access_no_check) + deferred_access_no_check--; + else + { + VEC (deferred_access_check,gc) *checks; + deferred_access *ptr; + + checks = (VEC_last (deferred_access, deferred_access_stack) + ->deferred_access_checks); + + VEC_pop (deferred_access, deferred_access_stack); + ptr = VEC_last (deferred_access, deferred_access_stack); + if (ptr->deferring_access_checks_kind == dk_no_deferred) + { + /* Check access. */ + perform_access_checks (checks); + } + else + { + /* Merge with parent. */ + int i, j; + deferred_access_check *chk, *probe; + + for (i = 0 ; + VEC_iterate (deferred_access_check, checks, i, chk) ; + ++i) + { + for (j = 0 ; + VEC_iterate (deferred_access_check, + ptr->deferred_access_checks, j, probe) ; + ++j) + { + if (probe->binfo == chk->binfo && + probe->decl == chk->decl && + probe->diag_decl == chk->diag_decl) + goto found; + } + /* Insert into parent's checks. */ + VEC_safe_push (deferred_access_check, gc, + ptr->deferred_access_checks, chk); + found:; + } + } + } +} + +/* Perform the access checks in CHECKS. The TREE_PURPOSE of each node + is the BINFO indicating the qualifying scope used to access the + DECL node stored in the TREE_VALUE of the node. */ + +void +perform_access_checks (VEC (deferred_access_check,gc)* checks) +{ + int i; + deferred_access_check *chk; + + if (!checks) + return; + + for (i = 0 ; VEC_iterate (deferred_access_check, checks, i, chk) ; ++i) + enforce_access (chk->binfo, chk->decl, chk->diag_decl); +} + +/* 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) +{ + perform_access_checks (get_deferred_access_checks ()); +} + +/* Defer checking the accessibility of DECL, when looked up in + BINFO. DIAG_DECL is the declaration to use to print diagnostics. */ + +void +perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl) +{ + int i; + deferred_access *ptr; + deferred_access_check *chk; + deferred_access_check *new_access; + + + /* Exit if we are in a context that no access checking is performed. + */ + if (deferred_access_no_check) + return; + + gcc_assert (TREE_CODE (binfo) == TREE_BINFO); + + ptr = VEC_last (deferred_access, deferred_access_stack); + + /* If we are not supposed to defer access checks, just check now. */ + if (ptr->deferring_access_checks_kind == dk_no_deferred) + { + enforce_access (binfo, decl, diag_decl); + return; + } + + /* See if we are already going to perform this check. */ + for (i = 0 ; + VEC_iterate (deferred_access_check, + ptr->deferred_access_checks, i, chk) ; + ++i) + { + if (chk->decl == decl && chk->binfo == binfo && + chk->diag_decl == diag_decl) + { + return; + } + } + /* If not, record the check. */ + new_access = + VEC_safe_push (deferred_access_check, gc, + ptr->deferred_access_checks, 0); + new_access->binfo = binfo; + new_access->decl = decl; + new_access->diag_decl = diag_decl; +} + +/* 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 (void) +{ + return current_stmt_tree ()->stmts_are_full_exprs_p; +} + +/* T is a statement. Add it to the statement-tree. This is the C++ + version. The C/ObjC frontends have a slightly different version of + this function. */ + +tree +add_stmt (tree t) +{ + enum tree_code code = TREE_CODE (t); + + if (EXPR_P (t) && code != LABEL_EXPR) + { + if (!EXPR_HAS_LOCATION (t)) + SET_EXPR_LOCATION (t, input_location); + + /* When we expand a statement-tree, we must know whether or not the + statements are full-expressions. We record that fact here. */ + STMT_IS_FULL_EXPR_P (t) = stmts_are_full_exprs_p (); + } + + /* Add T to the statement-tree. Non-side-effect statements need to be + recorded during statement expressions. */ + append_to_statement_list_force (t, &cur_stmt_list); + + return t; +} + +/* Returns the stmt_tree (if any) to which statements are currently + being added. If there is no active statement-tree, NULL is + returned. */ + +stmt_tree +current_stmt_tree (void) +{ + return (cfun + ? &cfun->language->base.x_stmt_tree + : &scope_chain->x_stmt_tree); +} + +/* If statements are full expressions, wrap STMT in a CLEANUP_POINT_EXPR. */ + +static tree +maybe_cleanup_point_expr (tree expr) +{ + if (!processing_template_decl && stmts_are_full_exprs_p ()) + expr = fold_build_cleanup_point_expr (TREE_TYPE (expr), expr); + return expr; +} + +/* Like maybe_cleanup_point_expr except have the type of the new expression be + void so we don't need to create a temporary variable to hold the inner + expression. The reason why we do this is because the original type might be + an aggregate and we cannot create a temporary variable for that type. */ + +static tree +maybe_cleanup_point_expr_void (tree expr) +{ + if (!processing_template_decl && stmts_are_full_exprs_p ()) + expr = fold_build_cleanup_point_expr (void_type_node, expr); + return expr; +} + + + +/* Create a declaration statement for the declaration given by the DECL. */ + +void +add_decl_expr (tree decl) +{ + tree r = build_stmt (DECL_EXPR, decl); + if (DECL_INITIAL (decl) + || (DECL_SIZE (decl) && TREE_SIDE_EFFECTS (DECL_SIZE (decl)))) + r = maybe_cleanup_point_expr_void (r); + add_stmt (r); +} + +/* Nonzero if TYPE is an anonymous union or struct type. We have to use a + flag for this because "A union for which objects or pointers are + declared is not an anonymous union" [class.union]. */ + +int +anon_aggr_type_p (tree node) +{ + return ANON_AGGR_TYPE_P (node); +} + +/* Finish a scope. */ + +tree +do_poplevel (tree stmt_list) +{ + tree block = NULL; + + if (stmts_are_full_exprs_p ()) + block = poplevel (kept_level_p (), 1, 0); + + stmt_list = pop_stmt_list (stmt_list); + + if (!processing_template_decl) + { + stmt_list = c_build_bind_expr (block, stmt_list); + /* ??? See c_end_compound_stmt re statement expressions. */ + } + + return stmt_list; +} + +/* Begin a new scope. */ + +static tree +do_pushlevel (scope_kind sk) +{ + tree ret = push_stmt_list (); + if (stmts_are_full_exprs_p ()) + begin_scope (sk, NULL); + return ret; +} + +/* Queue a cleanup. CLEANUP is an expression/statement to be executed + when the current scope is exited. EH_ONLY is true when this is not + meant to apply to normal control flow transfer. */ + +void +push_cleanup (tree decl, tree cleanup, bool eh_only) +{ + tree stmt = build_stmt (CLEANUP_STMT, NULL, cleanup, decl); + CLEANUP_EH_ONLY (stmt) = eh_only; + add_stmt (stmt); + CLEANUP_BODY (stmt) = push_stmt_list (); +} + +/* Begin a conditional that might contain a declaration. When generating + normal code, we want the declaration to appear before the statement + containing the conditional. When generating template code, we want the + conditional to be rendered as the raw DECL_EXPR. */ + +static void +begin_cond (tree *cond_p) +{ + if (processing_template_decl) + *cond_p = push_stmt_list (); +} + +/* Finish such a conditional. */ + +static void +finish_cond (tree *cond_p, tree expr) +{ + if (processing_template_decl) + { + tree cond = pop_stmt_list (*cond_p); + if (TREE_CODE (cond) == DECL_EXPR) + expr = cond; + } + *cond_p = expr; +} + +/* If *COND_P specifies a conditional with a declaration, transform the + loop such that + while (A x = 42) { } + for (; A x = 42;) { } + becomes + while (true) { A x = 42; if (!x) break; } + for (;;) { A x = 42; if (!x) break; } + The statement list for BODY will be empty if the conditional did + not declare anything. */ + +static void +simplify_loop_decl_cond (tree *cond_p, tree body) +{ + tree cond, if_stmt; + + if (!TREE_SIDE_EFFECTS (body)) + return; + + cond = *cond_p; + *cond_p = boolean_true_node; + + if_stmt = begin_if_stmt (); + cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0); + finish_if_stmt_cond (cond, if_stmt); + finish_break_stmt (); + finish_then_clause (if_stmt); + finish_if_stmt (if_stmt); +} + +/* Finish a goto-statement. */ + +tree +finish_goto_stmt (tree destination) +{ + if (TREE_CODE (destination) == IDENTIFIER_NODE) + destination = lookup_label (destination); + + /* We warn about unused labels with -Wunused. That means we have to + mark the used labels as used. */ + if (TREE_CODE (destination) == LABEL_DECL) + TREE_USED (destination) = 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); + + return add_stmt (build_stmt (GOTO_EXPR, destination)); +} + +/* COND is the condition-expression for an if, while, etc., + statement. Convert it to a boolean value, if appropriate. */ + +static tree +maybe_convert_cond (tree cond) +{ + /* Empty conditions remain empty. */ + if (!cond) + return NULL_TREE; + + /* Wait until we instantiate templates before doing conversion. */ + if (processing_template_decl) + return cond; + + /* Do the conversion. */ + cond = convert_from_reference (cond); + return condition_conversion (cond); +} + +/* Finish an expression-statement, whose EXPRESSION is as indicated. */ + +tree +finish_expr_stmt (tree expr) +{ + tree r = NULL_TREE; + + if (expr != NULL_TREE) + { + if (!processing_template_decl) + { + if (warn_sequence_point) + verify_sequence_points (expr); + expr = convert_to_void (expr, "statement"); + } + else if (!type_dependent_expression_p (expr)) + convert_to_void (build_non_dependent_expr (expr), "statement"); + + /* Simplification of inner statement expressions, compound exprs, + etc can result in us already having an EXPR_STMT. */ + if (TREE_CODE (expr) != CLEANUP_POINT_EXPR) + { + if (TREE_CODE (expr) != EXPR_STMT) + expr = build_stmt (EXPR_STMT, expr); + expr = maybe_cleanup_point_expr_void (expr); + } + + r = add_stmt (expr); + } + + finish_stmt (); + + return r; +} + + +/* Begin an if-statement. Returns a newly created IF_STMT if + appropriate. */ + +tree +begin_if_stmt (void) +{ + tree r, scope; + scope = do_pushlevel (sk_block); + r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE); + TREE_CHAIN (r) = scope; + begin_cond (&IF_COND (r)); + return r; +} + +/* Process the COND of an if-statement, which may be given by + IF_STMT. */ + +void +finish_if_stmt_cond (tree cond, tree if_stmt) +{ + finish_cond (&IF_COND (if_stmt), maybe_convert_cond (cond)); + add_stmt (if_stmt); + THEN_CLAUSE (if_stmt) = push_stmt_list (); +} + +/* Finish the then-clause of an if-statement, which may be given by + IF_STMT. */ + +tree +finish_then_clause (tree if_stmt) +{ + THEN_CLAUSE (if_stmt) = pop_stmt_list (THEN_CLAUSE (if_stmt)); + return if_stmt; +} + +/* Begin the else-clause of an if-statement. */ + +void +begin_else_clause (tree if_stmt) +{ + ELSE_CLAUSE (if_stmt) = push_stmt_list (); +} + +/* Finish the else-clause of an if-statement, which may be given by + IF_STMT. */ + +void +finish_else_clause (tree if_stmt) +{ + ELSE_CLAUSE (if_stmt) = pop_stmt_list (ELSE_CLAUSE (if_stmt)); +} + +/* Finish an if-statement. */ + +void +finish_if_stmt (tree if_stmt) +{ + tree scope = TREE_CHAIN (if_stmt); + TREE_CHAIN (if_stmt) = NULL; + add_stmt (do_poplevel (scope)); + finish_stmt (); + empty_body_warning (THEN_CLAUSE (if_stmt), ELSE_CLAUSE (if_stmt)); +} + +/* Begin a while-statement. Returns a newly created WHILE_STMT if + appropriate. */ + +tree +begin_while_stmt (void) +{ + tree r; + r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE); + add_stmt (r); + WHILE_BODY (r) = do_pushlevel (sk_block); + begin_cond (&WHILE_COND (r)); + return r; +} + +/* Process the COND of a while-statement, which may be given by + WHILE_STMT. */ + +void +finish_while_stmt_cond (tree cond, tree while_stmt) +{ + finish_cond (&WHILE_COND (while_stmt), maybe_convert_cond (cond)); + simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt)); +} + +/* Finish a while-statement, which may be given by WHILE_STMT. */ + +void +finish_while_stmt (tree while_stmt) +{ + WHILE_BODY (while_stmt) = do_poplevel (WHILE_BODY (while_stmt)); + finish_stmt (); +} + +/* Begin a do-statement. Returns a newly created DO_STMT if + appropriate. */ + +tree +begin_do_stmt (void) +{ + tree r = build_stmt (DO_STMT, NULL_TREE, NULL_TREE); + add_stmt (r); + DO_BODY (r) = push_stmt_list (); + return r; +} + +/* Finish the body of a do-statement, which may be given by DO_STMT. */ + +void +finish_do_body (tree do_stmt) +{ + DO_BODY (do_stmt) = pop_stmt_list (DO_BODY (do_stmt)); +} + +/* Finish a do-statement, which may be given by DO_STMT, and whose + COND is as indicated. */ + +void +finish_do_stmt (tree cond, tree do_stmt) +{ + cond = maybe_convert_cond (cond); + DO_COND (do_stmt) = cond; + finish_stmt (); +} + +/* Finish a return-statement. The EXPRESSION returned, if any, is as + indicated. */ + +tree +finish_return_stmt (tree expr) +{ + tree r; + bool no_warning; + + expr = check_return_expr (expr, &no_warning); + + if (flag_openmp && !check_omp_return ()) + return error_mark_node; + if (!processing_template_decl) + { + if (DECL_DESTRUCTOR_P (current_function_decl) + || (DECL_CONSTRUCTOR_P (current_function_decl) + && targetm.cxx.cdtor_returns_this ())) + { + /* Similarly, all destructors must run destructors for + base-classes before returning. So, all returns in a + destructor get sent to the DTOR_LABEL; finish_function emits + code to return a value there. */ + return finish_goto_stmt (cdtor_label); + } + } + + r = build_stmt (RETURN_EXPR, expr); + TREE_NO_WARNING (r) |= no_warning; + r = maybe_cleanup_point_expr_void (r); + r = add_stmt (r); + finish_stmt (); + + return r; +} + +/* Begin a for-statement. Returns a new FOR_STMT if appropriate. */ + +tree +begin_for_stmt (void) +{ + tree r; + + r = build_stmt (FOR_STMT, NULL_TREE, NULL_TREE, + NULL_TREE, NULL_TREE); + + if (flag_new_for_scope > 0) + TREE_CHAIN (r) = do_pushlevel (sk_for); + + if (processing_template_decl) + FOR_INIT_STMT (r) = push_stmt_list (); + + return r; +} + +/* Finish the for-init-statement of a for-statement, which may be + given by FOR_STMT. */ + +void +finish_for_init_stmt (tree for_stmt) +{ + if (processing_template_decl) + FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt)); + add_stmt (for_stmt); + FOR_BODY (for_stmt) = do_pushlevel (sk_block); + begin_cond (&FOR_COND (for_stmt)); +} + +/* Finish the COND of a for-statement, which may be given by + FOR_STMT. */ + +void +finish_for_cond (tree cond, tree for_stmt) +{ + finish_cond (&FOR_COND (for_stmt), maybe_convert_cond (cond)); + simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt)); +} + +/* Finish the increment-EXPRESSION in a for-statement, which may be + given by FOR_STMT. */ + +void +finish_for_expr (tree expr, tree for_stmt) +{ + if (!expr) + return; + /* If EXPR is an overloaded function, issue an error; there is no + context available to use to perform overload resolution. */ + if (type_unknown_p (expr)) + { + cxx_incomplete_type_error (expr, TREE_TYPE (expr)); + expr = error_mark_node; + } + if (!processing_template_decl) + { + if (warn_sequence_point) + verify_sequence_points (expr); + expr = convert_to_void (expr, "3rd expression in for"); + } + else if (!type_dependent_expression_p (expr)) + convert_to_void (build_non_dependent_expr (expr), "3rd expression in for"); + expr = maybe_cleanup_point_expr_void (expr); + FOR_EXPR (for_stmt) = expr; +} + +/* Finish the body of a for-statement, which may be given by + FOR_STMT. The increment-EXPR for the loop must be + provided. */ + +void +finish_for_stmt (tree for_stmt) +{ + FOR_BODY (for_stmt) = do_poplevel (FOR_BODY (for_stmt)); + + /* Pop the scope for the body of the loop. */ + if (flag_new_for_scope > 0) + { + tree scope = TREE_CHAIN (for_stmt); + TREE_CHAIN (for_stmt) = NULL; + add_stmt (do_poplevel (scope)); + } + + finish_stmt (); +} + +/* Finish a break-statement. */ + +tree +finish_break_stmt (void) +{ + return add_stmt (build_stmt (BREAK_STMT)); +} + +/* Finish a continue-statement. */ + +tree +finish_continue_stmt (void) +{ + return add_stmt (build_stmt (CONTINUE_STMT)); +} + +/* Begin a switch-statement. Returns a new SWITCH_STMT if + appropriate. */ + +tree +begin_switch_stmt (void) +{ + tree r, scope; + + r = build_stmt (SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE); + + scope = do_pushlevel (sk_block); + TREE_CHAIN (r) = scope; + begin_cond (&SWITCH_STMT_COND (r)); + + return r; +} + +/* Finish the cond of a switch-statement. */ + +void +finish_switch_cond (tree cond, tree switch_stmt) +{ + tree orig_type = NULL; + if (!processing_template_decl) + { + tree index; + + /* Convert the condition to an integer or enumeration type. */ + cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, true); + if (cond == NULL_TREE) + { + error ("switch quantity not an integer"); + cond = error_mark_node; + } + orig_type = TREE_TYPE (cond); + if (cond != error_mark_node) + { + /* [stmt.switch] + + Integral promotions are performed. */ + cond = perform_integral_promotions (cond); + cond = maybe_cleanup_point_expr (cond); + } + + if (cond != error_mark_node) + { + index = get_unwidened (cond, NULL_TREE); + /* We can't strip a conversion from a signed type to an unsigned, + because if we did, int_fits_type_p would do the wrong thing + when checking case values for being in range, + and it's too hard to do the right thing. */ + if (TYPE_UNSIGNED (TREE_TYPE (cond)) + == TYPE_UNSIGNED (TREE_TYPE (index))) + cond = index; + } + } + finish_cond (&SWITCH_STMT_COND (switch_stmt), cond); + SWITCH_STMT_TYPE (switch_stmt) = orig_type; + add_stmt (switch_stmt); + push_switch (switch_stmt); + SWITCH_STMT_BODY (switch_stmt) = push_stmt_list (); +} + +/* Finish the body of a switch-statement, which may be given by + SWITCH_STMT. The COND to switch on is indicated. */ + +void +finish_switch_stmt (tree switch_stmt) +{ + tree scope; + + SWITCH_STMT_BODY (switch_stmt) = + pop_stmt_list (SWITCH_STMT_BODY (switch_stmt)); + pop_switch (); + finish_stmt (); + + scope = TREE_CHAIN (switch_stmt); + TREE_CHAIN (switch_stmt) = NULL; + add_stmt (do_poplevel (scope)); +} + +/* Begin a try-block. Returns a newly-created TRY_BLOCK if + appropriate. */ + +tree +begin_try_block (void) +{ + tree r = build_stmt (TRY_BLOCK, NULL_TREE, NULL_TREE); + add_stmt (r); + TRY_STMTS (r) = push_stmt_list (); + return r; +} + +/* Likewise, for a function-try-block. The block returned in + *COMPOUND_STMT is an artificial outer scope, containing the + function-try-block. */ + +tree +begin_function_try_block (tree *compound_stmt) +{ + tree r; + /* This outer scope does not exist in the C++ standard, but we need + a place to put __FUNCTION__ and similar variables. */ + *compound_stmt = begin_compound_stmt (0); + r = begin_try_block (); + FN_TRY_BLOCK_P (r) = 1; + return r; +} + +/* Finish a try-block, which may be given by TRY_BLOCK. */ + +void +finish_try_block (tree try_block) +{ + TRY_STMTS (try_block) = pop_stmt_list (TRY_STMTS (try_block)); + TRY_HANDLERS (try_block) = push_stmt_list (); +} + +/* Finish the body of a cleanup try-block, which may be given by + TRY_BLOCK. */ + +void +finish_cleanup_try_block (tree try_block) +{ + TRY_STMTS (try_block) = pop_stmt_list (TRY_STMTS (try_block)); +} + +/* Finish an implicitly generated try-block, with a cleanup is given + by CLEANUP. */ + +void +finish_cleanup (tree cleanup, tree try_block) +{ + TRY_HANDLERS (try_block) = cleanup; + CLEANUP_P (try_block) = 1; +} + +/* Likewise, for a function-try-block. */ + +void +finish_function_try_block (tree try_block) +{ + finish_try_block (try_block); + /* FIXME : something queer about CTOR_INITIALIZER somehow following + the try block, but moving it inside. */ + in_function_try_handler = 1; +} + +/* Finish a handler-sequence for a try-block, which may be given by + TRY_BLOCK. */ + +void +finish_handler_sequence (tree try_block) +{ + TRY_HANDLERS (try_block) = pop_stmt_list (TRY_HANDLERS (try_block)); + check_handlers (TRY_HANDLERS (try_block)); +} + +/* Finish the handler-seq for a function-try-block, given by + TRY_BLOCK. COMPOUND_STMT is the outer block created by + begin_function_try_block. */ + +void +finish_function_handler_sequence (tree try_block, tree compound_stmt) +{ + in_function_try_handler = 0; + finish_handler_sequence (try_block); + finish_compound_stmt (compound_stmt); +} + +/* Begin a handler. Returns a HANDLER if appropriate. */ + +tree +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. */ + HANDLER_BODY (r) = do_pushlevel (sk_catch); + + return r; +} + +/* Finish the handler-parameters for a handler, which may be given by + HANDLER. DECL is the declaration for the catch parameter, or NULL + if this is a `catch (...)' clause. */ + +void +finish_handler_parms (tree decl, tree handler) +{ + tree type = NULL_TREE; + if (processing_template_decl) + { + if (decl) + { + decl = pushdecl (decl); + decl = push_template_decl (decl); + HANDLER_PARMS (handler) = decl; + type = TREE_TYPE (decl); + } + } + else + 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 (tree handler) +{ + if (!processing_template_decl) + expand_end_catch_block (); + HANDLER_BODY (handler) = do_poplevel (HANDLER_BODY (handler)); +} + +/* Begin a compound statement. FLAGS contains some bits that control the + behavior and context. If BCS_NO_SCOPE is set, the compound statement + does not define a scope. If BCS_FN_BODY is set, this is the outermost + block of a function. If BCS_TRY_BLOCK is set, this is the block + created on behalf of a TRY statement. Returns a token to be passed to + finish_compound_stmt. */ + +tree +begin_compound_stmt (unsigned int flags) +{ + tree r; + + if (flags & BCS_NO_SCOPE) + { + r = push_stmt_list (); + STATEMENT_LIST_NO_SCOPE (r) = 1; + + /* 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 (false); + } + else + r = do_pushlevel (flags & BCS_TRY_BLOCK ? sk_try : sk_block); + + /* When processing a template, we need to remember where the braces were, + so that we can set up identical scopes when instantiating the template + later. BIND_EXPR is a handy candidate for this. + Note that do_poplevel won't create a BIND_EXPR itself here (and thus + result in nested BIND_EXPRs), since we don't build BLOCK nodes when + processing templates. */ + if (processing_template_decl) + { + r = build3 (BIND_EXPR, NULL, NULL, r, NULL); + BIND_EXPR_TRY_BLOCK (r) = (flags & BCS_TRY_BLOCK) != 0; + BIND_EXPR_BODY_BLOCK (r) = (flags & BCS_FN_BODY) != 0; + TREE_SIDE_EFFECTS (r) = 1; + } + + return r; +} + +/* Finish a compound-statement, which is given by STMT. */ + +void +finish_compound_stmt (tree stmt) +{ + if (TREE_CODE (stmt) == BIND_EXPR) + BIND_EXPR_BODY (stmt) = do_poplevel (BIND_EXPR_BODY (stmt)); + else if (STATEMENT_LIST_NO_SCOPE (stmt)) + stmt = pop_stmt_list (stmt); + else + { + /* Destroy any ObjC "super" receivers that may have been + created. */ + objc_clear_super_receiver (); + + stmt = do_poplevel (stmt); + } + + /* ??? See c_end_compound_stmt wrt statement expressions. */ + add_stmt (stmt); + finish_stmt (); +} + +/* Finish an asm-statement, whose components are a STRING, some + OUTPUT_OPERANDS, some INPUT_OPERANDS, and some CLOBBERS. Also note + whether the asm-statement should be considered volatile. */ + +tree +finish_asm_stmt (int volatile_p, tree string, tree output_operands, + tree input_operands, tree clobbers) +{ + tree r; + tree t; + int ninputs = list_length (input_operands); + int noutputs = list_length (output_operands); + + if (!processing_template_decl) + { + const char *constraint; + const char **oconstraints; + bool allows_mem, allows_reg, is_inout; + tree operand; + int i; + + oconstraints = (const char **) alloca (noutputs * sizeof (char *)); + + string = resolve_asm_operand_names (string, output_operands, + input_operands); + + for (i = 0, t = output_operands; t; t = TREE_CHAIN (t), ++i) + { + operand = TREE_VALUE (t); + + /* ??? Really, this should not be here. Users should be using a + proper lvalue, dammit. But there's a long history of using + casts in the output operands. In cases like longlong.h, this + becomes a primitive form of typechecking -- if the cast can be + removed, then the output operand had a type of the proper width; + otherwise we'll get an error. Gross, but ... */ + STRIP_NOPS (operand); + + if (!lvalue_or_else (operand, lv_asm)) + operand = error_mark_node; + + if (operand != error_mark_node + && (TREE_READONLY (operand) + || CP_TYPE_CONST_P (TREE_TYPE (operand)) + /* Functions are not modifiable, even though they are + lvalues. */ + || TREE_CODE (TREE_TYPE (operand)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (operand)) == METHOD_TYPE + /* If it's an aggregate and any field is const, then it is + effectively const. */ + || (CLASS_TYPE_P (TREE_TYPE (operand)) + && C_TYPE_FIELDS_READONLY (TREE_TYPE (operand))))) + readonly_error (operand, "assignment (via 'asm' output)", 0); + + constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); + oconstraints[i] = constraint; + + if (parse_output_constraint (&constraint, i, ninputs, noutputs, + &allows_mem, &allows_reg, &is_inout)) + { + /* If the operand is going to end up in memory, + mark it addressable. */ + if (!allows_reg && !cxx_mark_addressable (operand)) + operand = error_mark_node; + } + else + operand = error_mark_node; + + TREE_VALUE (t) = operand; + } + + for (i = 0, t = input_operands; t; ++i, t = TREE_CHAIN (t)) + { + constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t))); + operand = decay_conversion (TREE_VALUE (t)); + + /* If the type of the operand hasn't been determined (e.g., + because it involves an overloaded function), then issue + an error message. There's no context available to + resolve the overloading. */ + if (TREE_TYPE (operand) == unknown_type_node) + { + error ("type of asm operand %qE could not be determined", + TREE_VALUE (t)); + operand = error_mark_node; + } + + if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0, + oconstraints, &allows_mem, &allows_reg)) + { + /* If the operand is going to end up in memory, + mark it addressable. */ + if (!allows_reg && allows_mem) + { + /* Strip the nops as we allow this case. FIXME, this really + should be rejected or made deprecated. */ + STRIP_NOPS (operand); + if (!cxx_mark_addressable (operand)) + operand = error_mark_node; + } + } + else + operand = error_mark_node; + + TREE_VALUE (t) = operand; + } + } + + r = build_stmt (ASM_EXPR, string, + output_operands, input_operands, + clobbers); + ASM_VOLATILE_P (r) = volatile_p || noutputs == 0; + r = maybe_cleanup_point_expr_void (r); + return add_stmt (r); +} + +/* Finish a label with the indicated NAME. */ + +tree +finish_label_stmt (tree name) +{ + tree decl = define_label (input_location, name); + + if (decl == error_mark_node) + return error_mark_node; + + return add_stmt (build_stmt (LABEL_EXPR, decl)); +} + +/* Finish a series of declarations for local labels. G++ allows users + to declare "local" labels, i.e., labels with scope. This extension + is useful when writing code involving statement-expressions. */ + +void +finish_label_decl (tree name) +{ + tree decl = declare_local_label (name); + add_decl_expr (decl); +} + +/* When DECL goes out of scope, make sure that CLEANUP is executed. */ + +void +finish_decl_cleanup (tree decl, tree cleanup) +{ + push_cleanup (decl, cleanup, false); +} + +/* If the current scope exits with an exception, run CLEANUP. */ + +void +finish_eh_cleanup (tree cleanup) +{ + push_cleanup (NULL, cleanup, true); +} + +/* 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. */ + +void +finish_mem_initializers (tree mem_inits) +{ + /* Reorder the MEM_INITS so that they are in the order they appeared + in the source program. */ + mem_inits = nreverse (mem_inits); + + if (processing_template_decl) + add_stmt (build_min_nt (CTOR_INITIALIZER, mem_inits)); + else + emit_mem_initializers (mem_inits); +} + +/* Finish a parenthesized expression EXPR. */ + +tree +finish_parenthesized_expr (tree expr) +{ + if (EXPR_P (expr)) + /* This inhibits warnings in c_common_truthvalue_conversion. */ + TREE_NO_WARNING (expr) = 1; + + if (TREE_CODE (expr) == OFFSET_REF) + /* [expr.unary.op]/3 The qualified id of a pointer-to-member must not be + enclosed in parentheses. */ + PTRMEM_OK_P (expr) = 0; + + if (TREE_CODE (expr) == STRING_CST) + PAREN_STRING_LITERAL_P (expr) = 1; + + 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) +{ + gcc_assert (TREE_CODE (decl) == FIELD_DECL); + + if (!object) + { + if (current_function_decl + && DECL_STATIC_FUNCTION_P (current_function_decl)) + error ("invalid use of member %q+D in static member function", decl); + else + error ("invalid use of non-static data member %q+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, NULL_TREE); + } + 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) + { + error ("object missing in reference to %q+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_qualified_name (TREE_TYPE (decl), + qualifying_scope, + DECL_NAME (decl), + /*template_p=*/false); + + perform_or_defer_access_check (TYPE_BINFO (access_type), decl, + 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; + + /* If we're not checking, return immediately. */ + if (deferred_access_no_check) + return; + + /* 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 + /* It is possible for qualifying type to be a TEMPLATE_TYPE_PARM + or similar in a default argument value. */ + && CLASS_TYPE_P (qualifying_type) + && !dependent_type_p (qualifying_type)) + perform_or_defer_access_check (TYPE_BINFO (qualifying_type), decl, + 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 '&'. TEMPLATE_P is true iff + the qualified-id was of the form "A::template B". TEMPLATE_ARG_P + is true iff this qualified name appears as a template argument. */ + +tree +finish_qualified_id_expr (tree qualifying_class, + tree expr, + bool done, + bool address_p, + bool template_p, + bool template_arg_p) +{ + gcc_assert (TYPE_P (qualifying_class)); + + if (error_operand_p (expr)) + return error_mark_node; + + if (DECL_P (expr) || BASELINK_P (expr)) + mark_used (expr); + + if (template_p) + check_template_keyword (expr); + + /* 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; + } + + /* Within the scope of a class, turn references to non-static + members into expression of the form "this->...". */ + if (template_arg_p) + /* But, within a template argument, we do not want make the + transformation, as there is no "this" pointer. */ + ; + else 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 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); + /* If so, the expression may be relative to the current + class. */ + if (!shared_member_p (fns) + && 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 (void) +{ + return push_stmt_list (); +} + +/* Process the final expression of a statement expression. EXPR can be + NULL, if the final expression is empty. Return a STATEMENT_LIST + containing all the statements in the statement-expression, or + ERROR_MARK_NODE if there was an error. */ + +tree +finish_stmt_expr_expr (tree expr, tree stmt_expr) +{ + if (error_operand_p (expr)) + return error_mark_node; + + /* If the last statement does not have "void" type, then the value + of the last statement is the value of the entire expression. */ + if (expr) + { + tree type = TREE_TYPE (expr); + + if (processing_template_decl) + { + expr = build_stmt (EXPR_STMT, expr); + expr = add_stmt (expr); + /* Mark the last statement so that we can recognize it as such at + template-instantiation time. */ + EXPR_STMT_STMT_EXPR_RESULT (expr) = 1; + } + else if (VOID_TYPE_P (type)) + { + /* Just treat this like an ordinary statement. */ + expr = finish_expr_stmt (expr); + } + else + { + /* It actually has a value we need to deal with. First, force it + to be an rvalue so that we won't need to build up a copy + constructor call later when we try to assign it to something. */ + expr = force_rvalue (expr); + if (error_operand_p (expr)) + return error_mark_node; + + /* Update for array-to-pointer decay. */ + type = TREE_TYPE (expr); + + /* Wrap it in a CLEANUP_POINT_EXPR and add it to the list like a + normal statement, but don't convert to void or actually add + the EXPR_STMT. */ + if (TREE_CODE (expr) != CLEANUP_POINT_EXPR) + expr = maybe_cleanup_point_expr (expr); + add_stmt (expr); + } + + /* The type of the statement-expression is the type of the last + expression. */ + TREE_TYPE (stmt_expr) = type; + } + + return stmt_expr; +} + +/* 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 (tree stmt_expr, bool has_no_scope) +{ + tree type; + tree result; + + if (error_operand_p (stmt_expr)) + return error_mark_node; + + gcc_assert (TREE_CODE (stmt_expr) == STATEMENT_LIST); + + type = TREE_TYPE (stmt_expr); + result = pop_stmt_list (stmt_expr); + TREE_TYPE (result) = type; + + if (processing_template_decl) + { + result = build_min (STMT_EXPR, type, result); + TREE_SIDE_EFFECTS (result) = 1; + STMT_EXPR_NO_SCOPE (result) = has_no_scope; + } + else if (CLASS_TYPE_P (type)) + { + /* Wrap the statement-expression in a TARGET_EXPR so that the + temporary object created by the final expression is destroyed at + the end of the full-expression containing the + statement-expression. */ + result = force_target_expr (type, result); + } + + 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); + } + + return fn; +} + +/* Generate an expression for `FN (ARGS)'. + + If DISALLOW_VIRTUAL is true, the call to FN will be not generated + as a virtual call, even if FN is virtual. (This flag is set when + encountering an expression where the function name is explicitly + qualified. For example a call to `X::f' never generates a virtual + call.) + + Returns code for the call. */ + +tree +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; + + /* ARGS should be a list of arguments. */ + gcc_assert (!args || TREE_CODE (args) == TREE_LIST); + gcc_assert (!TYPE_P (fn)); + + 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, NULL_TREE); + 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); + } + + if (is_overloaded_fn (fn)) + fn = baselink_for_fns (fn); + + result = NULL_TREE; + if (BASELINK_P (fn)) + { + tree object; + + /* A call to a member function. From [over.call.func]: + + If the keyword this is in scope and refers to the class of + that member function, or a derived class thereof, then the + function call is transformed into a qualified function call + using (*this) as the postfix-expression to the left of the + . operator.... [Otherwise] a contrived object of type T + becomes the implied object argument. + + This paragraph is unclear about this situation: + + struct A { void f(); }; + struct B : public A {}; + struct C : public A { void g() { B::f(); }}; + + In particular, for `B::f', this paragraph does not make clear + whether "the class of that member function" refers to `A' or + to `B'. We believe it refers to `B'. */ + if (current_class_type + && DERIVED_FROM_P (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)), + current_class_type) + && current_class_ref) + object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)), + NULL); + else + { + tree representative_fn; + + representative_fn = BASELINK_FUNCTIONS (fn); + if (TREE_CODE (representative_fn) == TEMPLATE_ID_EXPR) + representative_fn = TREE_OPERAND (representative_fn, 0); + representative_fn = get_first_fn (representative_fn); + object = build_dummy_object (DECL_CONTEXT (representative_fn)); + } + + if (processing_template_decl) + { + if (type_dependent_expression_p (object)) + return build_nt (CALL_EXPR, orig_fn, orig_args, NULL_TREE); + object = build_non_dependent_expr (object); + } + + result = build_new_method_call (object, fn, args, NULL_TREE, + (disallow_virtual + ? LOOKUP_NONVIRTUAL : 0), + /*fn_p=*/NULL); + } + else if (is_overloaded_fn (fn)) + { + /* If the function is an overloaded builtin, resolve it. */ + if (TREE_CODE (fn) == FUNCTION_DECL + && (DECL_BUILT_IN_CLASS (fn) == BUILT_IN_NORMAL + || DECL_BUILT_IN_CLASS (fn) == BUILT_IN_MD)) + result = resolve_overloaded_builtin (fn, args); + + if (!result) + /* A call to a namespace-scope function. */ + result = build_new_function_call (fn, args, koenig_p); + } + else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR) + { + 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); + + if (processing_template_decl) + { + result = build3 (CALL_EXPR, TREE_TYPE (result), orig_fn, + orig_args, NULL_TREE); + KOENIG_LOOKUP_P (result) = koenig_p; + } + return result; +} + +/* Finish a call to a postfix increment or decrement or EXPR. (Which + is indicated by CODE, which should be POSTINCREMENT_EXPR or + POSTDECREMENT_EXPR.) */ + +tree +finish_increment_expr (tree expr, enum tree_code code) +{ + return build_x_unary_op (code, expr); +} + +/* Finish a use of `this'. Returns an expression for `this'. */ + +tree +finish_this_expr (void) +{ + tree result; + + if (current_class_ptr) + { + result = current_class_ptr; + } + else if (current_function_decl + && DECL_STATIC_FUNCTION_P (current_function_decl)) + { + error ("%<this%> is unavailable for static member functions"); + result = error_mark_node; + } + else + { + if (current_function_decl) + error ("invalid use of %<this%> in non-member function"); + else + error ("invalid use of %<this%> at top level"); + result = error_mark_node; + } + + return result; +} + +/* 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_pseudo_destructor_expr (tree object, tree scope, tree destructor) +{ + if (destructor == error_mark_node) + return error_mark_node; + + gcc_assert (TYPE_P (destructor)); + + if (!processing_template_decl) + { + if (scope == error_mark_node) + { + error ("invalid qualifying scope in pseudo-destructor name"); + return error_mark_node; + } + if (scope && TYPE_P (scope) && !check_dtor_name (scope, destructor)) + { + error ("qualified type %qT does not match destructor name ~%qT", + scope, destructor); + return error_mark_node; + } + + + /* [expr.pseudo] says both: + + The type designated by the pseudo-destructor-name shall be + the same as the object type. + + and: + + The cv-unqualified versions of the object type and of the + type designated by the pseudo-destructor-name shall be the + same type. + + 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 ("%qE is not of type %qT", object, destructor); + return error_mark_node; + } + } + + return build3 (PSEUDO_DTOR_EXPR, void_type_node, object, scope, destructor); +} + +/* Finish an expression of the form CODE EXPR. */ + +tree +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 + expression. So check whether the result is folded before + setting TREE_NEGATED_INT. */ + if (code == NEGATE_EXPR && TREE_CODE (expr) == INTEGER_CST + && TREE_CODE (result) == INTEGER_CST + && !TYPE_UNSIGNED (TREE_TYPE (result)) + && INT_CST_LT (result, integer_zero_node)) + { + /* RESULT may be a cached INTEGER_CST, so we must copy it before + setting TREE_NEGATED_INT. */ + result = copy_node (result); + TREE_NEGATED_INT (result) = 1; + } + overflow_warning (result); + return result; +} + +/* Finish a compound-literal expression. TYPE is the type to which + the INITIALIZER_LIST is being cast. */ + +tree +finish_compound_literal (tree type, VEC(constructor_elt,gc) *initializer_list) +{ + tree var; + tree compound_literal; + + if (!TYPE_OBJ_P (type)) + { + error ("compound literal of non-object type %qT", type); + return error_mark_node; + } + + /* Build a CONSTRUCTOR for the INITIALIZER_LIST. */ + compound_literal = build_constructor (NULL_TREE, initializer_list); + if (processing_template_decl) + { + TREE_TYPE (compound_literal) = type; + /* Mark the expression as a compound literal. */ + TREE_HAS_CONSTRUCTOR (compound_literal) = 1; + return compound_literal; + } + + /* Create a temporary variable to represent the compound literal. */ + var = create_temporary_var (type); + if (!current_function_decl) + { + /* If this compound-literal appears outside of a function, then + the corresponding variable has static storage duration, just + like the variable in whose initializer it appears. */ + TREE_STATIC (var) = 1; + /* The variable has internal linkage, since there is no need to + reference it from another translation unit. */ + TREE_PUBLIC (var) = 0; + /* It must have a name, so that the name mangler can mangle it. */ + DECL_NAME (var) = make_anon_name (); + } + /* We must call pushdecl, since the gimplifier complains if the + variable has not been declared via a BIND_EXPR. */ + pushdecl (var); + /* Initialize the variable as we would any other variable with a + brace-enclosed initializer. */ + cp_finish_decl (var, compound_literal, + /*init_const_expr_p=*/false, + /*asmspec_tree=*/NULL_TREE, + LOOKUP_ONLYCONVERTING); + return var; +} + +/* Return the declaration for the function-name variable indicated by + ID. */ + +tree +finish_fname (tree id) +{ + tree decl; + + decl = fname_decl (C_RID_CODE (id), id); + if (processing_template_decl) + decl = DECL_NAME (decl); + return decl; +} + +/* Finish a translation unit. */ + +void +finish_translation_unit (void) +{ + /* In case there were missing closebraces, + get us back to the global binding level. */ + pop_everything (); + while (current_namespace != global_namespace) + pop_namespace (); + + /* Do file scope __FUNCTION__ et al. */ + finish_fname_decls (); +} + +/* Finish a template type parameter, specified as AGGR IDENTIFIER. + Returns the parameter. */ + +tree +finish_template_type_parm (tree aggr, tree identifier) +{ + if (aggr != class_type_node) + { + pedwarn ("template type parameters must use the keyword %<class%> or %<typename%>"); + aggr = class_type_node; + } + + return build_tree_list (aggr, identifier); +} + +/* Finish a template template parameter, specified as AGGR IDENTIFIER. + Returns the parameter. */ + +tree +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); + DECL_TEMPLATE_PARMS (tmpl) = current_template_parms; + DECL_TEMPLATE_RESULT (tmpl) = decl; + DECL_ARTIFICIAL (decl) = 1; + end_template_decl (); + + gcc_assert (DECL_TEMPLATE_PARMS (tmpl)); + + return finish_template_type_parm (aggr, tmpl); +} + +/* ARGUMENT is the default-argument value for a template template + parameter. If ARGUMENT is invalid, issue error messages and return + the ERROR_MARK_NODE. Otherwise, ARGUMENT itself is returned. */ + +tree +check_template_template_default_arg (tree argument) +{ + if (TREE_CODE (argument) != TEMPLATE_DECL + && TREE_CODE (argument) != TEMPLATE_TEMPLATE_PARM + && TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE) + { + if (TREE_CODE (argument) == TYPE_DECL) + error ("invalid use of type %qT as a default value for a template " + "template-parameter", TREE_TYPE (argument)); + else + error ("invalid default argument for a template template parameter"); + return error_mark_node; + } + + return argument; +} + +/* Begin a class definition, as indicated by T. */ + +tree +begin_class_definition (tree t, tree attributes) +{ + if (t == error_mark_node) + return error_mark_node; + + if (processing_template_parmlist) + { + error ("definition of %q#T inside template parameter list", t); + return error_mark_node; + } + /* A non-implicit typename comes from code like: + + template <typename T> struct A { + template <typename U> struct A<T>::B ... + + This is erroneous. */ + else if (TREE_CODE (t) == TYPENAME_TYPE) + { + error ("invalid definition of qualified type %qT", t); + t = error_mark_node; + } + + if (t == error_mark_node || ! IS_AGGR_TYPE (t)) + { + t = make_aggr_type (RECORD_TYPE); + pushtag (make_anon_name (), t, /*tag_scope=*/ts_current); + } + + /* Update the location of the decl. */ + DECL_SOURCE_LOCATION (TYPE_NAME (t)) = input_location; + + if (TYPE_BEING_DEFINED (t)) + { + t = make_aggr_type (TREE_CODE (t)); + pushtag (TYPE_IDENTIFIER (t), t, /*tag_scope=*/ts_current); + } + maybe_process_partial_specialization (t); + pushclass (t); + TYPE_BEING_DEFINED (t) = 1; + + cplus_decl_attributes (&t, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE); + + 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. */ + if (! TYPE_ANONYMOUS_P (t)) + { + struct c_fileinfo *finfo = get_fileinfo (input_filename); + CLASSTYPE_INTERFACE_ONLY (t) = finfo->interface_only; + SET_CLASSTYPE_INTERFACE_UNKNOWN_X + (t, finfo->interface_unknown); + } + reset_specialization(); + + /* Make a declaration for this class in its own scope. */ + build_self_reference (); + + return t; +} + +/* Finish the member declaration given by DECL. */ + +void +finish_member_declaration (tree decl) +{ + if (decl == error_mark_node || decl == NULL_TREE) + return; + + if (decl == void_type_node) + /* The COMPONENT was a friend, not a member, and so there's + nothing for us to do. */ + return; + + /* We should see only one DECL at a time. */ + gcc_assert (TREE_CHAIN (decl) == NULL_TREE); + + /* Set up access control for DECL. */ + TREE_PRIVATE (decl) + = (current_access_specifier == access_private_node); + TREE_PROTECTED (decl) + = (current_access_specifier == access_protected_node); + if (TREE_CODE (decl) == TEMPLATE_DECL) + { + TREE_PRIVATE (DECL_TEMPLATE_RESULT (decl)) = TREE_PRIVATE (decl); + TREE_PROTECTED (DECL_TEMPLATE_RESULT (decl)) = TREE_PROTECTED (decl); + } + + /* Mark the DECL as a member of the current class. */ + DECL_CONTEXT (decl) = current_class_type; + + /* [dcl.link] + + A C language linkage is ignored for the names of class members + and the member function type of class member functions. */ + if (DECL_LANG_SPECIFIC (decl) && DECL_LANGUAGE (decl) == lang_c) + SET_DECL_LANGUAGE (decl, lang_cplusplus); + + /* Put functions on the TYPE_METHODS list and everything else on the + TYPE_FIELDS list. Note that these are built up in reverse order. + We reverse them (to obtain declaration order) in finish_struct. */ + if (TREE_CODE (decl) == FUNCTION_DECL + || DECL_FUNCTION_TEMPLATE_P (decl)) + { + /* We also need to add this function to the + CLASSTYPE_METHOD_VEC. */ + if (add_method (current_class_type, decl, NULL_TREE)) + { + TREE_CHAIN (decl) = TYPE_METHODS (current_class_type); + TYPE_METHODS (current_class_type) = decl; + + maybe_add_class_template_decl_list (current_class_type, decl, + /*friend_p=*/0); + } + } + /* Enter the DECL into the scope of the class. */ + else if ((TREE_CODE (decl) == USING_DECL && !DECL_DEPENDENT_P (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 + searches the list in order, and we want a field name to + override a type name so that the "struct stat hack" will + work. In particular: + + struct S { enum E { }; int E } s; + s.E = 3; + + is valid. In addition, the FIELD_DECLs must be maintained in + declaration order so that class layout works as expected. + However, we don't need that order until class layout, so we + save a little time by putting FIELD_DECLs on in reverse order + here, and then reversing them in finish_struct_1. (We could + also keep a pointer to the correct insertion points in the + list.) */ + + if (TREE_CODE (decl) == TYPE_DECL) + TYPE_FIELDS (current_class_type) + = chainon (TYPE_FIELDS (current_class_type), decl); + else + { + TREE_CHAIN (decl) = TYPE_FIELDS (current_class_type); + TYPE_FIELDS (current_class_type) = decl; + } + + maybe_add_class_template_decl_list (current_class_type, decl, + /*friend_p=*/0); + } + + if (pch_file) + note_decl_for_pch (decl); +} + +/* DECL has been declared while we are building a PCH file. Perform + actions that we might normally undertake lazily, but which can be + performed now so that they do not have to be performed in + translation units which include the PCH file. */ + +void +note_decl_for_pch (tree decl) +{ + gcc_assert (pch_file); + + /* There's a good chance that we'll have to mangle names at some + point, even if only for emission in debugging information. */ + if ((TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == FUNCTION_DECL) + && !processing_template_decl) + mangle_decl (decl); +} + +/* Finish processing a complete template declaration. The PARMS are + the template parameters. */ + +void +finish_template_decl (tree parms) +{ + if (parms) + end_template_decl (); + else + end_specialization (); +} + +/* Finish processing a template-id (which names a type) of the form + NAME < ARGS >. Return the TYPE_DECL for the type named by the + template-id. If ENTERING_SCOPE is nonzero we are about to enter + the scope of template-id indicated. */ + +tree +finish_template_type (tree name, tree args, int entering_scope) +{ + tree decl; + + decl = lookup_template_class (name, args, + NULL_TREE, NULL_TREE, entering_scope, + tf_warning_or_error | tf_user); + if (decl != error_mark_node) + decl = TYPE_STUB_DECL (decl); + + return decl; +} + +/* 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 + ACCESS_SPECIFIER is one of + access_{default,public,protected_private}_node. For a virtual base + we set TREE_TYPE. */ + +tree +finish_base_specifier (tree base, tree access, bool virtual_p) +{ + tree result; + + if (base == error_mark_node) + { + error ("invalid base-class specification"); + result = NULL_TREE; + } + else if (! is_aggr_type (base, 1)) + result = NULL_TREE; + else + { + if (cp_type_quals (base) != 0) + { + error ("base class %qT has cv qualifiers", base); + base = TYPE_MAIN_VARIANT (base); + } + result = build_tree_list (access, base); + if (virtual_p) + TREE_TYPE (result) = integer_type_node; + } + + return result; +} + +/* Issue a diagnostic that NAME cannot be found in SCOPE. DECL is + what we found when we tried to do the lookup. */ + +void +qualified_name_lookup_error (tree scope, tree name, tree decl) +{ + if (scope == error_mark_node) + ; /* We already complained. */ + else if (TYPE_P (scope)) + { + if (!COMPLETE_TYPE_P (scope)) + error ("incomplete type %qT used in nested name specifier", scope); + else if (TREE_CODE (decl) == TREE_LIST) + { + error ("reference to %<%T::%D%> is ambiguous", scope, name); + print_candidates (decl); + } + else + error ("%qD is not a member of %qT", name, scope); + } + else if (scope != global_namespace) + error ("%qD is not a member of %qD", name, scope); + else + error ("%<::%D%> has not been declared", name); +} + +/* If FNS is a member function, a set of member functions, or a + template-id referring to one or more member functions, return a + BASELINK for FNS, incorporating the current access context. + Otherwise, return FNS unchanged. */ + +tree +baselink_for_fns (tree fns) +{ + tree fn; + tree cl; + + if (BASELINK_P (fns) + || error_operand_p (fns)) + return fns; + + fn = fns; + if (TREE_CODE (fn) == TEMPLATE_ID_EXPR) + fn = TREE_OPERAND (fn, 0); + fn = get_first_fn (fn); + if (!DECL_FUNCTION_MEMBER_P (fn)) + return fns; + + cl = currently_open_derived_class (DECL_CONTEXT (fn)); + if (!cl) + cl = DECL_CONTEXT (fn); + cl = TYPE_BINFO (cl); + return build_baselink (cl, cl, fns, /*optype=*/NULL_TREE); +} + +/* 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. + + 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 '&'. + TEMPLATE_P is true iff the qualified-id was of the form + "A::template B". TEMPLATE_ARG_P is true iff this qualified name + appears as a template argument. + + 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, + bool integral_constant_expression_p, + bool allow_non_integral_constant_expression_p, + bool *non_integral_constant_expression_p, + bool template_p, + bool done, + bool address_p, + bool template_arg_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, decl); + 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); + + /* Disallow uses of local variables from containing functions. */ + if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) + { + tree context = decl_function_context (decl); + if (context != NULL_TREE && context != current_function_decl + && ! TREE_STATIC (decl)) + { + error (TREE_CODE (decl) == VAR_DECL + ? "use of %<auto%> variable from containing function" + : "use of parameter from containing function"); + error (" %q+#D declared here", decl); + return error_mark_node; + } + } + } + + /* 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) + { + tree r; + + *idk = CP_ID_KIND_NONE; + if (TREE_CODE (decl) == TEMPLATE_PARM_INDEX) + decl = TEMPLATE_PARM_DECL (decl); + r = convert_from_reference (DECL_INITIAL (decl)); + + if (integral_constant_expression_p + && !dependent_type_p (TREE_TYPE (decl)) + && !(INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (r)))) + { + if (!allow_non_integral_constant_expression_p) + error ("template parameter %qD of type %qT 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 r; + } + /* 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) + { + used_types_insert (TREE_TYPE (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) + { + /* 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)) + { + if (address_p && done) + decl = finish_qualified_id_expr (scope, decl, + done, address_p, + template_p, + template_arg_p); + else if (dependent_type_p (scope)) + decl = build_qualified_name (/*type=*/NULL_TREE, + scope, + id_expression, + template_p); + else if (DECL_P (decl)) + decl = build_qualified_name (TREE_TYPE (decl), + scope, + id_expression, + template_p); + } + if (TREE_TYPE (decl)) + decl = convert_from_reference (decl); + return decl; + } + /* A TEMPLATE_ID already contains all the information we + need. */ + if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR) + return id_expression; + *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 convert_from_reference (decl); + /* The same is true for FIELD_DECL, but we also need to + make sure that the syntax is correct. */ + else if (TREE_CODE (decl) == FIELD_DECL) + { + /* Since SCOPE is NULL here, this is an unqualified name. + Access checking has been performed during name lookup + already. Turn off checking to avoid duplicate errors. */ + push_deferring_access_checks (dk_no_check); + decl = finish_non_static_data_member + (decl, current_class_ref, + /*qualifying_scope=*/NULL_TREE); + pop_deferring_access_checks (); + 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 + && ! DECL_INTEGRAL_CONSTANT_VAR_P (decl) + && ! builtin_valid_in_constant_expr_p (decl)) + { + if (!allow_non_integral_constant_expression_p) + { + error ("%qD 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 %qD as expression", decl); + return error_mark_node; + } + else if (DECL_CLASS_TEMPLATE_P (decl)) + { + error ("use of class template %qT as expression", decl); + return error_mark_node; + } + else if (TREE_CODE (decl) == TREE_LIST) + { + /* Ambiguous reference to base members. */ + error ("request for member %qD 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)) + decl = finish_qualified_id_expr (scope, + decl, + done, + address_p, + template_p, + template_arg_p); + else + { + tree r = convert_from_reference (decl); + + if (processing_template_decl && TYPE_P (scope)) + r = build_qualified_name (TREE_TYPE (r), + scope, decl, + template_p); + decl = r; + } + } + else if (TREE_CODE (decl) == FIELD_DECL) + { + /* Since SCOPE is NULL here, this is an unqualified name. + Access checking has been performed during name lookup + already. Turn off checking to avoid duplicate errors. */ + push_deferring_access_checks (dk_no_check); + decl = finish_non_static_data_member (decl, current_class_ref, + /*qualifying_scope=*/NULL_TREE); + pop_deferring_access_checks (); + } + else if (is_overloaded_fn (decl)) + { + tree first_fn; + + first_fn = decl; + if (TREE_CODE (first_fn) == TEMPLATE_ID_EXPR) + first_fn = TREE_OPERAND (first_fn, 0); + first_fn = get_first_fn (first_fn); + if (TREE_CODE (first_fn) == TEMPLATE_DECL) + first_fn = DECL_TEMPLATE_RESULT (first_fn); + + if (!really_overloaded_fn (decl)) + mark_used (first_fn); + + if (!template_arg_p + && TREE_CODE (first_fn) == FUNCTION_DECL + && DECL_FUNCTION_MEMBER_P (first_fn) + && !shared_member_p (decl)) + { + /* A set of member functions. */ + decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0); + return finish_class_member_access_expr (decl, id_expression, + /*template_p=*/false); + } + + decl = baselink_for_fns (decl); + } + else + { + 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, decl); + } + + decl = convert_from_reference (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 (tree expr) +{ + tree type; + + if (type_dependent_expression_p (expr)) + { + type = make_aggr_type (TYPEOF_TYPE); + TYPEOF_TYPE_EXPR (type) = expr; + + return type; + } + + type = unlowered_expr_type (expr); + + if (!type || type == unknown_type_node) + { + error ("type of %qE is unknown", expr); + return error_mark_node; + } + + return type; +} + +/* Perform C++-specific checks for __builtin_offsetof before calling + fold_offsetof. */ + +tree +finish_offsetof (tree expr) +{ + if (TREE_CODE (expr) == PSEUDO_DTOR_EXPR) + { + error ("cannot apply %<offsetof%> to destructor %<~%T%>", + TREE_OPERAND (expr, 2)); + return error_mark_node; + } + if (TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE + || TREE_CODE (TREE_TYPE (expr)) == METHOD_TYPE + || TREE_CODE (TREE_TYPE (expr)) == UNKNOWN_TYPE) + { + if (TREE_CODE (expr) == COMPONENT_REF + || TREE_CODE (expr) == COMPOUND_EXPR) + expr = TREE_OPERAND (expr, 1); + error ("cannot apply %<offsetof%> to member function %qD", expr); + return error_mark_node; + } + return fold_offsetof (expr, NULL_TREE); +} + +/* Called from expand_body via walk_tree. Replace all AGGR_INIT_EXPRs + with equivalent CALL_EXPRs. */ + +static tree +simplify_aggr_init_exprs_r (tree* tp, + int* walk_subtrees, + void* data ATTRIBUTE_UNUSED) +{ + /* 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 (*tp)) + { + *walk_subtrees = 0; + return NULL_TREE; + } + /* Only AGGR_INIT_EXPRs are interesting. */ + 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. */ + 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 (slot); + + 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 + { + gcc_assert (TREE_ADDRESSABLE (type)); + style = arg; + } + + if (style == ctor) + { + /* Replace the first argument to the ctor with the address of the + slot. */ + tree addr; + + args = TREE_CHAIN (args); + cxx_mark_addressable (slot); + addr = build1 (ADDR_EXPR, build_pointer_type (type), slot); + args = tree_cons (NULL_TREE, addr, args); + } + + call_expr = build3 (CALL_EXPR, + TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), + fn, args, NULL_TREE); + + if (style == arg) + { + /* Just mark it addressable here, and leave the rest to + expand_call{,_inline}. */ + cxx_mark_addressable (slot); + CALL_EXPR_RETURN_SLOT_OPT (call_expr) = true; + call_expr = build2 (MODIFY_EXPR, TREE_TYPE (call_expr), slot, call_expr); + } + else if (style == pcc) + { + /* 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); + pop_deferring_access_checks (); + call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (slot), call_expr, slot); + } + + *tp = call_expr; +} + +/* Emit all thunks to FN that should be emitted when FN is emitted. */ + +static void +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 + is so that you can know statically the entire set of thunks that + will ever be needed for a given virtual function, thereby + enabling you to output all the thunks with the function itself. */ + if (DECL_VIRTUAL_P (fn)) + { + tree thunk; + + for (thunk = DECL_THUNKS (fn); thunk; thunk = TREE_CHAIN (thunk)) + { + 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 + gcc_assert (!DECL_THUNKS (thunk)); + } + } +} + +/* Generate RTL for FN. */ + +void +expand_body (tree fn) +{ + 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); + + /* This function is only called from cgraph, or recursively from + emit_associated_thunks. In neither case should we be currently + generating trees for a function. */ + gcc_assert (function_depth == 0); + + tree_rest_of_compilation (fn); + + current_function_decl = saved_function; + + 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. */ + if (processing_template_decl) + { + /* Normally, collection only occurs in rest_of_compilation. So, + if we don't collect here, we never collect junk generated + during the processing of templates until we hit a + non-template function. It's not safe to do this inside a + nested class, though, as the parser may have local state that + is not a GC root. */ + if (!function_depth) + ggc_collect (); + return; + } + + /* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs. */ + walk_tree_without_duplicates (&DECL_SAVED_TREE (fn), + simplify_aggr_init_exprs_r, + NULL); + + /* If this is a constructor or destructor body, we have to clone + it. */ + if (maybe_clone_body (fn)) + { + /* We don't want to process FN again, so pretend we've written + it out, even though we haven't. */ + TREE_ASM_WRITTEN (fn) = 1; + return; + } + + /* 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); + + /* We make a decision about linkage for these functions at the end + of the compilation. Until that point, we do not want the back + end to output them -- but we do want it to see the bodies of + these functions so that it can inline them as appropriate. */ + if (DECL_DECLARED_INLINE_P (fn) || DECL_IMPLICIT_INSTANTIATION (fn)) + { + if (DECL_INTERFACE_KNOWN (fn)) + /* We've already made a decision as to how this function will + be handled. */; + else if (!at_eof) + { + DECL_EXTERNAL (fn) = 1; + DECL_NOT_REALLY_EXTERN (fn) = 1; + note_vague_linkage_fn (fn); + /* A non-template inline function with external linkage will + always be COMDAT. As we must eventually determine the + linkage of all functions, and as that causes writes to + the data mapped in from the PCH file, it's advantageous + to mark the functions at this point. */ + if (!DECL_IMPLICIT_INSTANTIATION (fn)) + { + /* This function must have external linkage, as + otherwise DECL_INTERFACE_KNOWN would have been + set. */ + gcc_assert (TREE_PUBLIC (fn)); + comdat_linkage (fn); + DECL_INTERFACE_KNOWN (fn) = 1; + } + } + else + import_export_decl (fn); + + /* If the user wants us to keep all inline functions, then mark + this function as needed so that finish_file will make sure to + output it later. */ + if (flag_keep_inline_functions && DECL_DECLARED_INLINE_P (fn)) + mark_needed (fn); + } + + /* There's no reason to do any of the work here if we're only doing + semantic analysis; this code just generates RTL. */ + if (flag_syntax_only) + return; + + function_depth++; + + /* Expand or defer, at the whim of the compilation unit manager. */ + cgraph_finalize_function (fn, function_depth > 1); + + function_depth--; +} + +struct nrv_data +{ + tree var; + tree result; + htab_t visited; +}; + +/* Helper function for walk_tree, used by finalize_nrv below. */ + +static tree +finalize_nrv_r (tree* tp, int* walk_subtrees, void* data) +{ + struct nrv_data *dp = (struct nrv_data *)data; + void **slot; + + /* No need to walk into types. There wouldn't be any need to walk into + non-statements, except that we have to consider STMT_EXPRs. */ + if (TYPE_P (*tp)) + *walk_subtrees = 0; + /* Change all returns to just refer to the RESULT_DECL; this is a nop, + but differs from using NULL_TREE in that it indicates that we care + about the value of the RESULT_DECL. */ + else if (TREE_CODE (*tp) == RETURN_EXPR) + TREE_OPERAND (*tp, 0) = dp->result; + /* Change all cleanups for the NRV to only run when an exception is + thrown. */ + else if (TREE_CODE (*tp) == CLEANUP_STMT + && CLEANUP_DECL (*tp) == dp->var) + CLEANUP_EH_ONLY (*tp) = 1; + /* Replace the DECL_EXPR for the NRV with an initialization of the + RESULT_DECL, if needed. */ + else if (TREE_CODE (*tp) == DECL_EXPR + && DECL_EXPR_DECL (*tp) == dp->var) + { + tree init; + if (DECL_INITIAL (dp->var) + && DECL_INITIAL (dp->var) != error_mark_node) + { + init = build2 (INIT_EXPR, void_type_node, dp->result, + DECL_INITIAL (dp->var)); + DECL_INITIAL (dp->var) = error_mark_node; + } + else + init = build_empty_stmt (); + SET_EXPR_LOCUS (init, EXPR_LOCUS (*tp)); + *tp = init; + } + /* And replace all uses of the NRV with the RESULT_DECL. */ + else if (*tp == dp->var) + *tp = dp->result; + + /* Avoid walking into the same tree more than once. Unfortunately, we + can't just use walk_tree_without duplicates because it would only call + us for the first occurrence of dp->var in the function body. */ + slot = htab_find_slot (dp->visited, *tp, INSERT); + if (*slot) + *walk_subtrees = 0; + else + *slot = *tp; + + /* Keep iterating. */ + return NULL_TREE; +} + +/* Called from finish_function to implement the named return value + optimization by overriding all the RETURN_EXPRs and pertinent + CLEANUP_STMTs and replacing all occurrences of VAR with RESULT, the + RESULT_DECL for the function. */ + +void +finalize_nrv (tree *tp, tree var, tree result) +{ + struct nrv_data data; + + /* Copy debugging information from VAR to RESULT. */ + DECL_NAME (result) = DECL_NAME (var); + DECL_ARTIFICIAL (result) = DECL_ARTIFICIAL (var); + DECL_IGNORED_P (result) = DECL_IGNORED_P (var); + DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (var); + DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (var); + /* Don't forget that we take its address. */ + TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (var); + + data.var = var; + data.result = result; + data.visited = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL); + walk_tree (tp, finalize_nrv_r, &data, 0); + htab_delete (data.visited); +} + +/* For all elements of CLAUSES, validate them vs OpenMP constraints. + Remove any elements from the list that are invalid. */ + +tree +finish_omp_clauses (tree clauses) +{ + bitmap_head generic_head, firstprivate_head, lastprivate_head; + tree c, t, *pc = &clauses; + const char *name; + + bitmap_obstack_initialize (NULL); + bitmap_initialize (&generic_head, &bitmap_default_obstack); + bitmap_initialize (&firstprivate_head, &bitmap_default_obstack); + bitmap_initialize (&lastprivate_head, &bitmap_default_obstack); + + for (pc = &clauses, c = clauses; c ; c = *pc) + { + bool remove = false; + + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_SHARED: + name = "shared"; + goto check_dup_generic; + case OMP_CLAUSE_PRIVATE: + name = "private"; + goto check_dup_generic; + case OMP_CLAUSE_REDUCTION: + name = "reduction"; + goto check_dup_generic; + case OMP_CLAUSE_COPYPRIVATE: + name = "copyprivate"; + goto check_dup_generic; + case OMP_CLAUSE_COPYIN: + name = "copyin"; + goto check_dup_generic; + check_dup_generic: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + if (DECL_P (t)) + error ("%qD is not a variable in clause %qs", t, name); + else + error ("%qE is not a variable in clause %qs", t, name); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t)) + || bitmap_bit_p (&lastprivate_head, DECL_UID (t))) + { + error ("%qD appears more than once in data clauses", t); + remove = true; + } + else + bitmap_set_bit (&generic_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_FIRSTPRIVATE: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + error ("%qE is not a variable in clause %<firstprivate%>", t); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + { + error ("%qE appears more than once in data clauses", t); + remove = true; + } + else + bitmap_set_bit (&firstprivate_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_LASTPRIVATE: + t = OMP_CLAUSE_DECL (c); + if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + if (processing_template_decl) + break; + error ("%qE is not a variable in clause %<lastprivate%>", t); + remove = true; + } + else if (bitmap_bit_p (&generic_head, DECL_UID (t)) + || bitmap_bit_p (&lastprivate_head, DECL_UID (t))) + { + error ("%qE appears more than once in data clauses", t); + remove = true; + } + else + bitmap_set_bit (&lastprivate_head, DECL_UID (t)); + break; + + case OMP_CLAUSE_IF: + t = OMP_CLAUSE_IF_EXPR (c); + t = maybe_convert_cond (t); + if (t == error_mark_node) + remove = true; + OMP_CLAUSE_IF_EXPR (c) = t; + break; + + case OMP_CLAUSE_NUM_THREADS: + t = OMP_CLAUSE_NUM_THREADS_EXPR (c); + if (t == error_mark_node) + remove = true; + else if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && !type_dependent_expression_p (t)) + { + error ("num_threads expression must be integral"); + remove = true; + } + break; + + case OMP_CLAUSE_SCHEDULE: + t = OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c); + if (t == NULL) + ; + else if (t == error_mark_node) + remove = true; + else if (!INTEGRAL_TYPE_P (TREE_TYPE (t)) + && !type_dependent_expression_p (t)) + { + error ("schedule chunk size expression must be integral"); + remove = true; + } + break; + + case OMP_CLAUSE_NOWAIT: + case OMP_CLAUSE_ORDERED: + case OMP_CLAUSE_DEFAULT: + break; + + default: + gcc_unreachable (); + } + + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + + for (pc = &clauses, c = clauses; c ; c = *pc) + { + enum tree_code c_kind = OMP_CLAUSE_CODE (c); + bool remove = false; + bool need_complete_non_reference = false; + bool need_default_ctor = false; + bool need_copy_ctor = false; + bool need_copy_assignment = false; + bool need_implicitly_determined = false; + tree type, inner_type; + + switch (c_kind) + { + case OMP_CLAUSE_SHARED: + name = "shared"; + need_implicitly_determined = true; + break; + case OMP_CLAUSE_PRIVATE: + name = "private"; + need_complete_non_reference = true; + need_default_ctor = true; + need_implicitly_determined = true; + break; + case OMP_CLAUSE_FIRSTPRIVATE: + name = "firstprivate"; + need_complete_non_reference = true; + need_copy_ctor = true; + need_implicitly_determined = true; + break; + case OMP_CLAUSE_LASTPRIVATE: + name = "lastprivate"; + need_complete_non_reference = true; + need_copy_assignment = true; + need_implicitly_determined = true; + break; + case OMP_CLAUSE_REDUCTION: + name = "reduction"; + need_implicitly_determined = true; + break; + case OMP_CLAUSE_COPYPRIVATE: + name = "copyprivate"; + need_copy_assignment = true; + break; + case OMP_CLAUSE_COPYIN: + name = "copyin"; + need_copy_assignment = true; + break; + default: + pc = &OMP_CLAUSE_CHAIN (c); + continue; + } + + t = OMP_CLAUSE_DECL (c); + if (processing_template_decl + && TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL) + { + pc = &OMP_CLAUSE_CHAIN (c); + continue; + } + + switch (c_kind) + { + case OMP_CLAUSE_LASTPRIVATE: + if (!bitmap_bit_p (&firstprivate_head, DECL_UID (t))) + need_default_ctor = true; + break; + + case OMP_CLAUSE_REDUCTION: + if (AGGREGATE_TYPE_P (TREE_TYPE (t)) + || POINTER_TYPE_P (TREE_TYPE (t))) + { + error ("%qE has invalid type for %<reduction%>", t); + remove = true; + } + else if (FLOAT_TYPE_P (TREE_TYPE (t))) + { + enum tree_code r_code = OMP_CLAUSE_REDUCTION_CODE (c); + switch (r_code) + { + case PLUS_EXPR: + case MULT_EXPR: + case MINUS_EXPR: + break; + default: + error ("%qE has invalid type for %<reduction(%s)%>", + t, operator_name_info[r_code].name); + remove = true; + } + } + break; + + case OMP_CLAUSE_COPYIN: + if (TREE_CODE (t) != VAR_DECL || !DECL_THREAD_LOCAL_P (t)) + { + error ("%qE must be %<threadprivate%> for %<copyin%>", t); + remove = true; + } + break; + + default: + break; + } + + if (need_complete_non_reference) + { + t = require_complete_type (t); + if (t == error_mark_node) + remove = true; + else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE) + { + error ("%qE has reference type for %qs", t, name); + remove = true; + } + } + if (need_implicitly_determined) + { + const char *share_name = NULL; + + if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t)) + share_name = "threadprivate"; + else switch (cxx_omp_predetermined_sharing (t)) + { + case OMP_CLAUSE_DEFAULT_UNSPECIFIED: + break; + case OMP_CLAUSE_DEFAULT_SHARED: + share_name = "shared"; + break; + case OMP_CLAUSE_DEFAULT_PRIVATE: + share_name = "private"; + break; + default: + gcc_unreachable (); + } + if (share_name) + { + error ("%qE is predetermined %qs for %qs", + t, share_name, name); + remove = true; + } + } + + /* We're interested in the base element, not arrays. */ + inner_type = type = TREE_TYPE (t); + while (TREE_CODE (inner_type) == ARRAY_TYPE) + inner_type = TREE_TYPE (inner_type); + + /* Check for special function availability by building a call to one. + Save the results, because later we won't be in the right context + for making these queries. */ + if (CLASS_TYPE_P (inner_type) + && (need_default_ctor || need_copy_ctor || need_copy_assignment) + && !type_dependent_expression_p (t)) + { + int save_errorcount = errorcount; + tree info; + + /* Always allocate 3 elements for simplicity. These are the + function decls for the ctor, dtor, and assignment op. + This layout is known to the three lang hooks, + cxx_omp_clause_default_init, cxx_omp_clause_copy_init, + and cxx_omp_clause_assign_op. */ + info = make_tree_vec (3); + CP_OMP_CLAUSE_INFO (c) = info; + + if (need_default_ctor + || (need_copy_ctor + && !TYPE_HAS_TRIVIAL_INIT_REF (inner_type))) + { + if (need_default_ctor) + t = NULL; + else + { + t = build_int_cst (build_pointer_type (inner_type), 0); + t = build1 (INDIRECT_REF, inner_type, t); + t = build_tree_list (NULL, t); + } + t = build_special_member_call (NULL_TREE, + complete_ctor_identifier, + t, inner_type, LOOKUP_NORMAL); + t = get_callee_fndecl (t); + TREE_VEC_ELT (info, 0) = t; + } + + if ((need_default_ctor || need_copy_ctor) + && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (inner_type)) + { + t = build_int_cst (build_pointer_type (inner_type), 0); + t = build1 (INDIRECT_REF, inner_type, t); + t = build_special_member_call (t, complete_dtor_identifier, + NULL, inner_type, LOOKUP_NORMAL); + t = get_callee_fndecl (t); + TREE_VEC_ELT (info, 1) = t; + } + + if (need_copy_assignment + && !TYPE_HAS_TRIVIAL_ASSIGN_REF (inner_type)) + { + t = build_int_cst (build_pointer_type (inner_type), 0); + t = build1 (INDIRECT_REF, inner_type, t); + t = build_special_member_call (t, ansi_assopname (NOP_EXPR), + build_tree_list (NULL, t), + inner_type, LOOKUP_NORMAL); + + /* We'll have called convert_from_reference on the call, which + may well have added an indirect_ref. It's unneeded here, + and in the way, so kill it. */ + if (TREE_CODE (t) == INDIRECT_REF) + t = TREE_OPERAND (t, 0); + + t = get_callee_fndecl (t); + TREE_VEC_ELT (info, 2) = t; + } + + if (errorcount != save_errorcount) + remove = true; + } + + if (remove) + *pc = OMP_CLAUSE_CHAIN (c); + else + pc = &OMP_CLAUSE_CHAIN (c); + } + + bitmap_obstack_release (NULL); + return clauses; +} + +/* For all variables in the tree_list VARS, mark them as thread local. */ + +void +finish_omp_threadprivate (tree vars) +{ + tree t; + + /* Mark every variable in VARS to be assigned thread local storage. */ + for (t = vars; t; t = TREE_CHAIN (t)) + { + tree v = TREE_PURPOSE (t); + + /* If V had already been marked threadprivate, it doesn't matter + whether it had been used prior to this point. */ + if (TREE_USED (v) + && (DECL_LANG_SPECIFIC (v) == NULL + || !CP_DECL_THREADPRIVATE_P (v))) + error ("%qE declared %<threadprivate%> after first use", v); + else if (! TREE_STATIC (v) && ! DECL_EXTERNAL (v)) + error ("automatic variable %qE cannot be %<threadprivate%>", v); + else if (! COMPLETE_TYPE_P (TREE_TYPE (v))) + error ("%<threadprivate%> %qE has incomplete type", v); + else if (TREE_STATIC (v) && TYPE_P (CP_DECL_CONTEXT (v))) + error ("%<threadprivate%> %qE is not file, namespace " + "or block scope variable", v); + else + { + /* Allocate a LANG_SPECIFIC structure for V, if needed. */ + if (DECL_LANG_SPECIFIC (v) == NULL) + { + retrofit_lang_decl (v); + + /* Make sure that DECL_DISCRIMINATOR_P continues to be true + after the allocation of the lang_decl structure. */ + if (DECL_DISCRIMINATOR_P (v)) + DECL_LANG_SPECIFIC (v)->decl_flags.u2sel = 1; + } + + if (! DECL_THREAD_LOCAL_P (v)) + { + DECL_TLS_MODEL (v) = decl_default_tls_model (v); + /* If rtl has been already set for this var, call + make_decl_rtl once again, so that encode_section_info + has a chance to look at the new decl flags. */ + if (DECL_RTL_SET_P (v)) + make_decl_rtl (v); + } + CP_DECL_THREADPRIVATE_P (v) = 1; + } + } +} + +/* Build an OpenMP structured block. */ + +tree +begin_omp_structured_block (void) +{ + return do_pushlevel (sk_omp); +} + +tree +finish_omp_structured_block (tree block) +{ + return do_poplevel (block); +} + +/* Similarly, except force the retention of the BLOCK. */ + +tree +begin_omp_parallel (void) +{ + keep_next_level (true); + return begin_omp_structured_block (); +} + +tree +finish_omp_parallel (tree clauses, tree body) +{ + tree stmt; + + body = finish_omp_structured_block (body); + + stmt = make_node (OMP_PARALLEL); + TREE_TYPE (stmt) = void_type_node; + OMP_PARALLEL_CLAUSES (stmt) = clauses; + OMP_PARALLEL_BODY (stmt) = body; + + return add_stmt (stmt); +} + +/* Build and validate an OMP_FOR statement. CLAUSES, BODY, COND, INCR + are directly for their associated operands in the statement. DECL + and INIT are a combo; if DECL is NULL then INIT ought to be a + MODIFY_EXPR, and the DECL should be extracted. PRE_BODY are + optional statements that need to go before the loop into its + sk_omp scope. */ + +tree +finish_omp_for (location_t locus, tree decl, tree init, tree cond, + tree incr, tree body, tree pre_body) +{ + if (decl == NULL) + { + if (init != NULL) + switch (TREE_CODE (init)) + { + case MODIFY_EXPR: + decl = TREE_OPERAND (init, 0); + init = TREE_OPERAND (init, 1); + break; + case MODOP_EXPR: + if (TREE_CODE (TREE_OPERAND (init, 1)) == NOP_EXPR) + { + decl = TREE_OPERAND (init, 0); + init = TREE_OPERAND (init, 2); + } + break; + default: + break; + } + + if (decl == NULL) + { + error ("expected iteration declaration or initialization"); + return NULL; + } + } + + if (type_dependent_expression_p (decl) + || type_dependent_expression_p (init) + || (cond && type_dependent_expression_p (cond)) + || (incr && type_dependent_expression_p (incr))) + { + tree stmt; + + if (cond == NULL) + { + error ("%Hmissing controlling predicate", &locus); + return NULL; + } + + if (incr == NULL) + { + error ("%Hmissing increment expression", &locus); + return NULL; + } + + stmt = make_node (OMP_FOR); + + /* This is really just a place-holder. We'll be decomposing this + again and going through the build_modify_expr path below when + we instantiate the thing. */ + init = build2 (MODIFY_EXPR, void_type_node, decl, init); + + TREE_TYPE (stmt) = void_type_node; + OMP_FOR_INIT (stmt) = init; + OMP_FOR_COND (stmt) = cond; + OMP_FOR_INCR (stmt) = incr; + OMP_FOR_BODY (stmt) = body; + OMP_FOR_PRE_BODY (stmt) = pre_body; + + SET_EXPR_LOCATION (stmt, locus); + return add_stmt (stmt); + } + + if (!DECL_P (decl)) + { + error ("expected iteration declaration or initialization"); + return NULL; + } + + if (pre_body == NULL || IS_EMPTY_STMT (pre_body)) + pre_body = NULL; + else if (! processing_template_decl) + { + add_stmt (pre_body); + pre_body = NULL; + } + init = build_modify_expr (decl, NOP_EXPR, init); + return c_finish_omp_for (locus, decl, init, cond, incr, body, pre_body); +} + +void +finish_omp_atomic (enum tree_code code, tree lhs, tree rhs) +{ + tree orig_lhs; + tree orig_rhs; + bool dependent_p; + tree stmt; + + orig_lhs = lhs; + orig_rhs = rhs; + dependent_p = false; + stmt = NULL_TREE; + + /* Even in a template, we can detect invalid uses of the atomic + pragma if neither LHS nor RHS is type-dependent. */ + if (processing_template_decl) + { + dependent_p = (type_dependent_expression_p (lhs) + || type_dependent_expression_p (rhs)); + if (!dependent_p) + { + lhs = build_non_dependent_expr (lhs); + rhs = build_non_dependent_expr (rhs); + } + } + if (!dependent_p) + { + stmt = c_finish_omp_atomic (code, lhs, rhs); + if (stmt == error_mark_node) + return; + } + if (processing_template_decl) + { + stmt = build2 (OMP_ATOMIC, void_type_node, orig_lhs, orig_rhs); + OMP_ATOMIC_DEPENDENT_P (stmt) = 1; + OMP_ATOMIC_CODE (stmt) = code; + } + add_stmt (stmt); +} + +void +finish_omp_barrier (void) +{ + tree fn = built_in_decls[BUILT_IN_GOMP_BARRIER]; + tree stmt = finish_call_expr (fn, NULL, false, false); + finish_expr_stmt (stmt); +} + +void +finish_omp_flush (void) +{ + tree fn = built_in_decls[BUILT_IN_SYNCHRONIZE]; + tree stmt = finish_call_expr (fn, NULL, false, false); + finish_expr_stmt (stmt); +} + +/* True if OpenMP sharing attribute of DECL is predetermined. */ + +enum omp_clause_default_kind +cxx_omp_predetermined_sharing (tree decl) +{ + enum omp_clause_default_kind kind; + + kind = c_omp_predetermined_sharing (decl); + if (kind != OMP_CLAUSE_DEFAULT_UNSPECIFIED) + return kind; + + /* Static data members are predetermined as shared. */ + if (TREE_STATIC (decl)) + { + tree ctx = CP_DECL_CONTEXT (decl); + if (TYPE_P (ctx) && IS_AGGR_TYPE (ctx)) + return OMP_CLAUSE_DEFAULT_SHARED; + } + + return OMP_CLAUSE_DEFAULT_UNSPECIFIED; +} + +void +init_cp_semantics (void) +{ +} + +#include "gt-cp-semantics.h" |