diff options
Diffstat (limited to 'gcc-4.8.1/gcc/cp/semantics.c')
-rw-r--r-- | gcc-4.8.1/gcc/cp/semantics.c | 9784 |
1 files changed, 0 insertions, 9784 deletions
diff --git a/gcc-4.8.1/gcc/cp/semantics.c b/gcc-4.8.1/gcc/cp/semantics.c deleted file mode 100644 index 8a7fe3807..000000000 --- a/gcc-4.8.1/gcc/cp/semantics.c +++ /dev/null @@ -1,9784 +0,0 @@ -/* 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-2013 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 3, 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 COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "tree.h" -#include "cp-tree.h" -#include "c-family/c-common.h" -#include "c-family/c-objc.h" -#include "tree-inline.h" -#include "intl.h" -#include "toplev.h" -#include "flags.h" -#include "timevar.h" -#include "diagnostic.h" -#include "cgraph.h" -#include "tree-iterator.h" -#include "vec.h" -#include "target.h" -#include "gimple.h" -#include "bitmap.h" -#include "hash-table.h" - -static bool verify_constant (tree, bool, bool *, bool *); -#define VERIFY_CONSTANT(X) \ -do { \ - if (verify_constant ((X), allow_non_constant, non_constant_p, overflow_p)) \ - return t; \ - } while (0) - -/* 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 finalize_nrv_r (tree *, int *, void *); -static tree capture_decltype (tree); - - -/* 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 vector 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 vector. `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 GTY(()) deferred_access { - /* A vector 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, va_gc> * GTY(()) deferred_access_checks; - - /* The current mode of access checks. */ - enum deferring_kind deferring_access_checks_kind; - -} deferred_access; - -/* Data for deferred access checking. */ -static GTY(()) vec<deferred_access, va_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 e = {NULL, deferring}; - vec_safe_push (deferred_access_stack, e); - } -} - -/* Resume deferring access checks again after we stopped doing - this previously. */ - -void -resume_deferring_access_checks (void) -{ - if (!deferred_access_no_check) - deferred_access_stack->last().deferring_access_checks_kind = dk_deferred; -} - -/* Stop deferring access checks. */ - -void -stop_deferring_access_checks (void) -{ - if (!deferred_access_no_check) - deferred_access_stack->last().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 - deferred_access_stack->pop (); -} - -/* 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, va_gc> * -get_deferred_access_checks (void) -{ - if (deferred_access_no_check) - return NULL; - else - return (deferred_access_stack->last().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, va_gc> *checks; - deferred_access *ptr; - - checks = (deferred_access_stack->last ().deferred_access_checks); - - deferred_access_stack->pop (); - ptr = &deferred_access_stack->last (); - if (ptr->deferring_access_checks_kind == dk_no_deferred) - { - /* Check access. */ - perform_access_checks (checks, tf_warning_or_error); - } - else - { - /* Merge with parent. */ - int i, j; - deferred_access_check *chk, *probe; - - FOR_EACH_VEC_SAFE_ELT (checks, i, chk) - { - FOR_EACH_VEC_SAFE_ELT (ptr->deferred_access_checks, j, probe) - { - 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 (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. If CHECKS is empty - or we aren't in SFINAE context or all the checks succeed return TRUE, - otherwise FALSE. */ - -bool -perform_access_checks (vec<deferred_access_check, va_gc> *checks, - tsubst_flags_t complain) -{ - int i; - deferred_access_check *chk; - location_t loc = input_location; - bool ok = true; - - if (!checks) - return true; - - FOR_EACH_VEC_SAFE_ELT (checks, i, chk) - { - input_location = chk->loc; - ok &= enforce_access (chk->binfo, chk->decl, chk->diag_decl, complain); - } - - input_location = loc; - return (complain & tf_error) ? true : ok; -} - -/* 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'. Return value like perform_access_checks above. */ - -bool -perform_deferred_access_checks (tsubst_flags_t complain) -{ - return perform_access_checks (get_deferred_access_checks (), complain); -} - -/* Defer checking the accessibility of DECL, when looked up in - BINFO. DIAG_DECL is the declaration to use to print diagnostics. - Return value like perform_access_checks above. */ - -bool -perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl, - tsubst_flags_t complain) -{ - int i; - deferred_access *ptr; - deferred_access_check *chk; - - - /* Exit if we are in a context that no access checking is performed. - */ - if (deferred_access_no_check) - return true; - - gcc_assert (TREE_CODE (binfo) == TREE_BINFO); - - ptr = &deferred_access_stack->last (); - - /* If we are not supposed to defer access checks, just check now. */ - if (ptr->deferring_access_checks_kind == dk_no_deferred) - { - bool ok = enforce_access (binfo, decl, diag_decl, complain); - return (complain & tf_error) ? true : ok; - } - - /* See if we are already going to perform this check. */ - FOR_EACH_VEC_SAFE_ELT (ptr->deferred_access_checks, i, chk) - { - if (chk->decl == decl && chk->binfo == binfo && - chk->diag_decl == diag_decl) - { - return true; - } - } - /* If not, record the check. */ - deferred_access_check new_access = {binfo, decl, diag_decl, input_location}; - vec_safe_push (ptr->deferred_access_checks, new_access); - - return true; -} - -/* 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. */ - gcc_checking_assert (!stmt_list_stack->is_empty ()); - append_to_statement_list_force (t, &cur_stmt_list); - - return t; -} - -/* Returns the stmt_tree to which statements are currently being added. */ - -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. */ - -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 (input_location, 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); -} - -/* 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 (input_location, 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 (input_location, 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 (expr == NULL_TREE) - /* Empty condition in 'for'. */ - gcc_assert (empty_expr_stmt_p (cond)); - else if (check_for_bare_parameter_packs (expr)) - expr = error_mark_node; - else if (!empty_expr_stmt_p (cond)) - expr = build2 (COMPOUND_EXPR, TREE_TYPE (expr), cond, expr); - } - *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 = cp_build_unary_op (TRUTH_NOT_EXPR, cond, 0, tf_warning_or_error); - 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 - { - destination = mark_rvalue_use (destination); - if (!processing_template_decl) - { - destination = cp_convert (ptr_type_node, destination, - tf_warning_or_error); - if (error_operand_p (destination)) - return NULL_TREE; - destination - = fold_build_cleanup_point_expr (TREE_TYPE (destination), - destination); - } - } - - check_goto (destination); - - return add_stmt (build_stmt (input_location, GOTO_EXPR, destination)); -} - -/* COND is the condition-expression for an if, while, etc., - statement. Convert it to a boolean value, if appropriate. - In addition, verify sequence points if -Wsequence-point is enabled. */ - -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; - - if (warn_sequence_point) - verify_sequence_points (cond); - - /* Do the conversion. */ - cond = convert_from_reference (cond); - - if (TREE_CODE (cond) == MODIFY_EXPR - && !TREE_NO_WARNING (cond) - && warn_parentheses) - { - warning (OPT_Wparentheses, - "suggest parentheses around assignment used as truth value"); - TREE_NO_WARNING (cond) = 1; - } - - 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, ICV_STATEMENT, tf_warning_or_error); - } - else if (!type_dependent_expression_p (expr)) - convert_to_void (build_non_dependent_expr (expr), ICV_STATEMENT, - tf_warning_or_error); - - if (check_for_bare_parameter_packs (expr)) - expr = error_mark_node; - - /* 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 (input_location, 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_cond); - r = build_stmt (input_location, IF_STMT, NULL_TREE, - NULL_TREE, NULL_TREE, 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 = IF_SCOPE (if_stmt); - IF_SCOPE (if_stmt) = NULL; - add_stmt (do_poplevel (scope)); - finish_stmt (); -} - -/* Begin a while-statement. Returns a newly created WHILE_STMT if - appropriate. */ - -tree -begin_while_stmt (void) -{ - tree r; - r = build_stmt (input_location, 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 (input_location, 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) -{ - tree body = DO_BODY (do_stmt) = pop_stmt_list (DO_BODY (do_stmt)); - - if (TREE_CODE (body) == STATEMENT_LIST && STATEMENT_LIST_TAIL (body)) - body = STATEMENT_LIST_TAIL (body)->stmt; - - if (IS_EMPTY_STMT (body)) - warning (OPT_Wempty_body, - "suggest explicit braces around empty body in %<do%> statement"); -} - -/* 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 (warn_sequence_point) - verify_sequence_points (expr); - - 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 (input_location, 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 the scope of a for-statement or a range-for-statement. - Both the returned trees are to be used in a call to - begin_for_stmt or begin_range_for_stmt. */ - -tree -begin_for_scope (tree *init) -{ - tree scope = NULL_TREE; - if (flag_new_for_scope > 0) - scope = do_pushlevel (sk_for); - - if (processing_template_decl) - *init = push_stmt_list (); - else - *init = NULL_TREE; - - return scope; -} - -/* Begin a for-statement. Returns a new FOR_STMT. - SCOPE and INIT should be the return of begin_for_scope, - or both NULL_TREE */ - -tree -begin_for_stmt (tree scope, tree init) -{ - tree r; - - r = build_stmt (input_location, FOR_STMT, NULL_TREE, NULL_TREE, - NULL_TREE, NULL_TREE, NULL_TREE); - - if (scope == NULL_TREE) - { - gcc_assert (!init || !(flag_new_for_scope > 0)); - if (!init) - scope = begin_for_scope (&init); - } - FOR_INIT_STMT (r) = init; - FOR_SCOPE (r) = scope; - - 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, ICV_THIRD_IN_FOR, - tf_warning_or_error); - } - else if (!type_dependent_expression_p (expr)) - convert_to_void (build_non_dependent_expr (expr), ICV_THIRD_IN_FOR, - tf_warning_or_error); - expr = maybe_cleanup_point_expr_void (expr); - if (check_for_bare_parameter_packs (expr)) - expr = error_mark_node; - 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. - It can also finish RANGE_FOR_STMT. */ - -void -finish_for_stmt (tree for_stmt) -{ - if (TREE_CODE (for_stmt) == RANGE_FOR_STMT) - RANGE_FOR_BODY (for_stmt) = do_poplevel (RANGE_FOR_BODY (for_stmt)); - else - 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 *scope_ptr = (TREE_CODE (for_stmt) == RANGE_FOR_STMT - ? &RANGE_FOR_SCOPE (for_stmt) - : &FOR_SCOPE (for_stmt)); - scope = *scope_ptr; - *scope_ptr = NULL; - add_stmt (do_poplevel (scope)); - } - - finish_stmt (); -} - -/* Begin a range-for-statement. Returns a new RANGE_FOR_STMT. - SCOPE and INIT should be the return of begin_for_scope, - or both NULL_TREE . - To finish it call finish_for_stmt(). */ - -tree -begin_range_for_stmt (tree scope, tree init) -{ - tree r; - - r = build_stmt (input_location, RANGE_FOR_STMT, - NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE); - - if (scope == NULL_TREE) - { - gcc_assert (!init || !(flag_new_for_scope > 0)); - if (!init) - scope = begin_for_scope (&init); - } - - /* RANGE_FOR_STMTs do not use nor save the init tree, so we - pop it now. */ - if (init) - pop_stmt_list (init); - RANGE_FOR_SCOPE (r) = scope; - - return r; -} - -/* Finish the head of a range-based for statement, which may - be given by RANGE_FOR_STMT. DECL must be the declaration - and EXPR must be the loop expression. */ - -void -finish_range_for_decl (tree range_for_stmt, tree decl, tree expr) -{ - RANGE_FOR_DECL (range_for_stmt) = decl; - RANGE_FOR_EXPR (range_for_stmt) = expr; - add_stmt (range_for_stmt); - RANGE_FOR_BODY (range_for_stmt) = do_pushlevel (sk_block); -} - -/* Finish a break-statement. */ - -tree -finish_break_stmt (void) -{ - /* In switch statements break is sometimes stylistically used after - a return statement. This can lead to spurious warnings about - control reaching the end of a non-void function when it is - inlined. Note that we are calling block_may_fallthru with - language specific tree nodes; this works because - block_may_fallthru returns true when given something it does not - understand. */ - if (!block_may_fallthru (cur_stmt_list)) - return void_zero_node; - return add_stmt (build_stmt (input_location, BREAK_STMT)); -} - -/* Finish a continue-statement. */ - -tree -finish_continue_stmt (void) -{ - return add_stmt (build_stmt (input_location, CONTINUE_STMT)); -} - -/* Begin a switch-statement. Returns a new SWITCH_STMT if - appropriate. */ - -tree -begin_switch_stmt (void) -{ - tree r, scope; - - scope = do_pushlevel (sk_cond); - r = build_stmt (input_location, SWITCH_STMT, NULL_TREE, NULL_TREE, NULL_TREE, 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) - { - /* 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 (check_for_bare_parameter_packs (cond)) - cond = error_mark_node; - else if (!processing_template_decl && warn_sequence_point) - verify_sequence_points (cond); - - 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 = SWITCH_STMT_SCOPE (switch_stmt); - SWITCH_STMT_SCOPE (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 (input_location, 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 (input_location, 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) - { - tree body = do_poplevel (BIND_EXPR_BODY (stmt)); - /* If the STATEMENT_LIST is empty and this BIND_EXPR isn't special, - discard the BIND_EXPR so it can be merged with the containing - STATEMENT_LIST. */ - if (TREE_CODE (body) == STATEMENT_LIST - && STATEMENT_LIST_HEAD (body) == NULL - && !BIND_EXPR_BODY_BLOCK (stmt) - && !BIND_EXPR_TRY_BLOCK (stmt)) - stmt = body; - else - BIND_EXPR_BODY (stmt) = body; - } - 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, some CLOBBERS and some - LABELS. 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 labels) -{ - 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 = XALLOCAVEC (const char *, noutputs); - - string = resolve_asm_operand_names (string, output_operands, - input_operands, labels); - - 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); - - operand = mark_lvalue_use (operand); - - if (!lvalue_or_else (operand, lv_asm, tf_warning_or_error)) - 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))))) - cxx_readonly_error (operand, lv_asm); - - 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))); - bool constraint_parsed - = parse_input_constraint (&constraint, i, ninputs, noutputs, 0, - oconstraints, &allows_mem, &allows_reg); - /* If the operand is going to end up in memory, don't call - decay_conversion. */ - if (constraint_parsed && !allows_reg && allows_mem) - operand = mark_lvalue_use (TREE_VALUE (t)); - else - operand = decay_conversion (TREE_VALUE (t), tf_warning_or_error); - - /* 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 (constraint_parsed) - { - /* 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 if (!allows_reg && !allows_mem) - { - /* If constraint allows neither register nor memory, - try harder to get a constant. */ - tree constop = maybe_constant_value (operand); - if (TREE_CONSTANT (constop)) - operand = constop; - } - } - else - operand = error_mark_node; - - TREE_VALUE (t) = operand; - } - } - - r = build_stmt (input_location, ASM_EXPR, string, - output_operands, input_operands, - clobbers, labels); - 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. Returns the new label. */ - -tree -finish_label_stmt (tree name) -{ - tree decl = define_label (input_location, name); - - if (decl == error_mark_node) - return error_mark_node; - - add_stmt (build_stmt (input_location, LABEL_EXPR, decl)); - - return 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) -{ - if (!at_function_scope_p ()) - { - error ("__label__ declarations are only allowed in function scopes"); - return; - } - - add_decl_expr (declare_local_label (name)); -} - -/* 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) - { - tree mem; - - for (mem = mem_inits; mem; mem = TREE_CHAIN (mem)) - { - /* If the TREE_PURPOSE is a TYPE_PACK_EXPANSION, skip the - check for bare parameter packs in the TREE_VALUE, because - any parameter packs in the TREE_VALUE have already been - bound as part of the TREE_PURPOSE. See - make_pack_expansion for more information. */ - if (TREE_CODE (TREE_PURPOSE (mem)) != TYPE_PACK_EXPANSION - && check_for_bare_parameter_packs (TREE_VALUE (mem))) - TREE_VALUE (mem) = error_mark_node; - } - - add_stmt (build_min_nt_loc (UNKNOWN_LOCATION, - 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 - || TREE_CODE (expr) == SCOPE_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) - { - tree scope = qualifying_scope; - if (scope == NULL_TREE) - scope = context_for_name_lookup (decl); - object = maybe_dummy_object (scope, NULL); - } - - object = maybe_resolve_dummy (object); - if (object == error_mark_node) - return error_mark_node; - - /* DR 613: Can use non-static data members without an associated - object in sizeof/decltype/alignof. */ - if (is_dummy_object (object) && cp_unevaluated_operand == 0 - && (!processing_template_decl || !current_class_ref)) - { - 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; - } - - if (current_class_ptr) - TREE_USED (current_class_ptr) = 1; - if (processing_template_decl && !qualifying_scope) - { - tree type = TREE_TYPE (decl); - - if (TREE_CODE (type) == REFERENCE_TYPE) - /* Quals on the object don't matter. */; - else - { - /* Set the cv qualifiers. */ - int quals = cp_type_quals (TREE_TYPE (object)); - - if (DECL_MUTABLE_P (decl)) - quals &= ~TYPE_QUAL_CONST; - - quals |= cp_type_quals (TREE_TYPE (decl)); - type = cp_build_qualified_type (type, quals); - } - - return (convert_from_reference - (build_min (COMPONENT_REF, type, object, decl, NULL_TREE))); - } - /* If PROCESSING_TEMPLATE_DECL is nonzero here, then - QUALIFYING_SCOPE is also non-null. Wrap this in a SCOPE_REF - for now. */ - else if (processing_template_decl) - return build_qualified_name (TREE_TYPE (decl), - qualifying_scope, - decl, - /*template_p=*/false); - else - { - tree access_type = TREE_TYPE (object); - - perform_or_defer_access_check (TYPE_BINFO (access_type), decl, - decl, tf_warning_or_error); - - /* 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, - tf_warning_or_error); - } -} - -/* If we are currently parsing a template and we encountered a typedef - TYPEDEF_DECL that is being accessed though CONTEXT, this function - adds the typedef to a list tied to the current template. - At template instantiation time, that list is walked and access check - performed for each typedef. - LOCATION is the location of the usage point of TYPEDEF_DECL. */ - -void -add_typedef_to_current_template_for_access_check (tree typedef_decl, - tree context, - location_t location) -{ - tree template_info = NULL; - tree cs = current_scope (); - - if (!is_typedef_decl (typedef_decl) - || !context - || !CLASS_TYPE_P (context) - || !cs) - return; - - if (CLASS_TYPE_P (cs) || TREE_CODE (cs) == FUNCTION_DECL) - template_info = get_template_info (cs); - - if (template_info - && TI_TEMPLATE (template_info) - && !currently_open_class (context)) - append_type_to_template_for_access_check (cs, typedef_decl, - context, location); -} - -/* 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 are parsing a template declaration and if decl is a typedef, - add it to a list tied to the template. - At template instantiation time, that list will be walked and - access check performed. */ - add_typedef_to_current_template_for_access_check (decl, - nested_name_specifier - ? nested_name_specifier - : DECL_CONTEXT (decl), - input_location); - - /* 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, tf_warning_or_error); -} - -/* 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, - tsubst_flags_t complain) -{ - 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, complain); - return expr; - } - - /* No need to check access within an enum. */ - if (TREE_CODE (qualifying_class) == ENUMERAL_TYPE) - 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) - { - push_deferring_access_checks (dk_no_check); - expr = finish_non_static_data_member (expr, NULL_TREE, - qualifying_class); - pop_deferring_access_checks (); - } - else if (BASELINK_P (expr) && !processing_template_decl) - { - /* See if any of the functions are non-static members. */ - /* If so, the expression may be relative to 'this'. */ - if (!shared_member_p (expr) - && current_class_ptr - && DERIVED_FROM_P (qualifying_class, - current_nonlambda_class_type ())) - expr = (build_class_member_access_expr - (maybe_dummy_object (qualifying_class, NULL), - expr, - BASELINK_ACCESS_BINFO (expr), - /*preserve_reference=*/false, - complain)); - 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, - complain); - } - else if (BASELINK_P (expr)) - ; - else - { - /* In a template, return a SCOPE_REF for most qualified-ids - so that we can check access at instantiation time. But if - we're looking at a member of the current instantiation, we - know we have access and building up the SCOPE_REF confuses - non-type template argument handling. */ - if (processing_template_decl - && !currently_open_class (qualifying_class)) - expr = build_qualified_name (TREE_TYPE (expr), - qualifying_class, expr, - template_p); - - expr = convert_from_reference (expr); - } - - 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)) - { - /* The type of the statement-expression is the type of the last - expression. */ - TREE_TYPE (stmt_expr) = error_mark_node; - 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 (input_location, 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, tf_warning_or_error); - 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)) - { - pop_stmt_list (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, tf_warning_or_error); - } - - return result; -} - -/* Returns the expression which provides the value of STMT_EXPR. */ - -tree -stmt_expr_value_expr (tree stmt_expr) -{ - tree t = STMT_EXPR_STMT (stmt_expr); - - if (TREE_CODE (t) == BIND_EXPR) - t = BIND_EXPR_BODY (t); - - if (TREE_CODE (t) == STATEMENT_LIST && STATEMENT_LIST_TAIL (t)) - t = STATEMENT_LIST_TAIL (t)->stmt; - - if (TREE_CODE (t) == EXPR_STMT) - t = EXPR_STMT_EXPR (t); - - return t; -} - -/* Return TRUE iff EXPR_STMT is an empty list of - expression statements. */ - -bool -empty_expr_stmt_p (tree expr_stmt) -{ - tree body = NULL_TREE; - - if (expr_stmt == void_zero_node) - return true; - - if (expr_stmt) - { - if (TREE_CODE (expr_stmt) == EXPR_STMT) - body = EXPR_STMT_EXPR (expr_stmt); - else if (TREE_CODE (expr_stmt) == STATEMENT_LIST) - body = expr_stmt; - } - - if (body) - { - if (TREE_CODE (body) == STATEMENT_LIST) - return tsi_end_p (tsi_start (body)); - else - return empty_expr_stmt_p (body); - } - return false; -} - -/* Perform Koenig lookup. FN is the postfix-expression representing - the function (or functions) to call; ARGS are the arguments to the - call; if INCLUDE_STD then the `std' namespace is automatically - considered an associated namespace (used in range-based for loops). - Returns the functions to be considered by overload resolution. */ - -tree -perform_koenig_lookup (tree fn, vec<tree, va_gc> *args, bool include_std, - tsubst_flags_t complain) -{ - tree identifier = NULL_TREE; - tree functions = NULL_TREE; - tree tmpl_args = NULL_TREE; - bool template_id = false; - - if (TREE_CODE (fn) == TEMPLATE_ID_EXPR) - { - /* Use a separate flag to handle null args. */ - template_id = true; - tmpl_args = TREE_OPERAND (fn, 1); - fn = TREE_OPERAND (fn, 0); - } - - /* 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) - && !any_dependent_template_arguments_p (tmpl_args)) - { - fn = lookup_arg_dependent (identifier, functions, args, include_std); - if (!fn) - { - /* The unqualified name could not be resolved. */ - if (complain) - fn = unqualified_fn_lookup_error (identifier); - else - fn = identifier; - } - } - - if (fn && template_id) - fn = build2 (TEMPLATE_ID_EXPR, unknown_type_node, fn, tmpl_args); - - return fn; -} - -/* Generate an expression for `FN (ARGS)'. This may change the - contents of 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, vec<tree, va_gc> **args, bool disallow_virtual, - bool koenig_p, tsubst_flags_t complain) -{ - tree result; - tree orig_fn; - vec<tree, va_gc> *orig_args = NULL; - - if (fn == error_mark_node) - return error_mark_node; - - gcc_assert (!TYPE_P (fn)); - - orig_fn = fn; - - if (processing_template_decl) - { - /* If the call expression is dependent, build a CALL_EXPR node - with no type; type_dependent_expression_p recognizes - expressions with no type as being dependent. */ - if (type_dependent_expression_p (fn) - || any_type_dependent_arguments_p (*args) - /* For a non-static member function that doesn't have an - explicit object argument, we need to specifically - test the type dependency of the "this" pointer because it - is not included in *ARGS even though it is considered to - be part of the list of arguments. Note that this is - related to CWG issues 515 and 1005. */ - || (TREE_CODE (fn) != COMPONENT_REF - && non_static_member_function_p (fn) - && current_class_ref - && type_dependent_expression_p (current_class_ref))) - { - result = build_nt_call_vec (fn, *args); - SET_EXPR_LOCATION (result, EXPR_LOC_OR_HERE (fn)); - KOENIG_LOOKUP_P (result) = koenig_p; - if (cfun) - { - do - { - tree fndecl = OVL_CURRENT (fn); - if (TREE_CODE (fndecl) != FUNCTION_DECL - || !TREE_THIS_VOLATILE (fndecl)) - break; - fn = OVL_NEXT (fn); - } - while (fn); - if (!fn) - current_function_returns_abnormally = 1; - } - return result; - } - orig_args = make_tree_vector_copy (*args); - if (!BASELINK_P (fn) - && TREE_CODE (fn) != PSEUDO_DTOR_EXPR - && TREE_TYPE (fn) != unknown_type_node) - fn = build_non_dependent_expr (fn); - make_args_non_dependent (*args); - } - - if (TREE_CODE (fn) == COMPONENT_REF) - { - tree member = TREE_OPERAND (fn, 1); - if (BASELINK_P (member)) - { - tree object = TREE_OPERAND (fn, 0); - return build_new_method_call (object, member, - args, NULL_TREE, - (disallow_virtual - ? LOOKUP_NORMAL | LOOKUP_NONVIRTUAL - : LOOKUP_NORMAL), - /*fn_p=*/NULL, - complain); - } - } - - 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. - - In this situation: - - struct A { void f(); }; - struct B : public A {}; - struct C : public A { void g() { B::f(); }}; - - "the class of that member function" refers to `A'. But 11.2 - [class.access.base] says that we need to convert 'this' to B* as - part of the access, so we pass 'B' to maybe_dummy_object. */ - - object = maybe_dummy_object (BINFO_TYPE (BASELINK_ACCESS_BINFO (fn)), - NULL); - - if (processing_template_decl) - { - if (type_dependent_expression_p (object)) - { - tree ret = build_nt_call_vec (orig_fn, orig_args); - release_tree_vector (orig_args); - return ret; - } - object = build_non_dependent_expr (object); - } - - result = build_new_method_call (object, fn, args, NULL_TREE, - (disallow_virtual - ? LOOKUP_NORMAL|LOOKUP_NONVIRTUAL - : LOOKUP_NORMAL), - /*fn_p=*/NULL, - complain); - } - 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 (input_location, fn, *args); - - if (!result) - { - if (warn_sizeof_pointer_memaccess - && !vec_safe_is_empty (*args) - && !processing_template_decl) - { - location_t sizeof_arg_loc[3]; - tree sizeof_arg[3]; - unsigned int i; - for (i = 0; i < 3; i++) - { - tree t; - - sizeof_arg_loc[i] = UNKNOWN_LOCATION; - sizeof_arg[i] = NULL_TREE; - if (i >= (*args)->length ()) - continue; - t = (**args)[i]; - if (TREE_CODE (t) != SIZEOF_EXPR) - continue; - if (SIZEOF_EXPR_TYPE_P (t)) - sizeof_arg[i] = TREE_TYPE (TREE_OPERAND (t, 0)); - else - sizeof_arg[i] = TREE_OPERAND (t, 0); - sizeof_arg_loc[i] = EXPR_LOCATION (t); - } - sizeof_pointer_memaccess_warning - (sizeof_arg_loc, fn, *args, - sizeof_arg, same_type_ignoring_top_level_qualifiers_p); - } - - /* A call to a namespace-scope function. */ - result = build_new_function_call (fn, args, koenig_p, complain); - } - } - else if (TREE_CODE (fn) == PSEUDO_DTOR_EXPR) - { - if (!vec_safe_is_empty (*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_op_call (fn, args, complain); - - if (!result) - /* A call where the function is unknown. */ - result = cp_build_function_call_vec (fn, args, complain); - - if (processing_template_decl && result != error_mark_node) - { - if (TREE_CODE (result) == INDIRECT_REF) - result = TREE_OPERAND (result, 0); - result = build_call_vec (TREE_TYPE (result), orig_fn, orig_args); - SET_EXPR_LOCATION (result, input_location); - KOENIG_LOOKUP_P (result) = koenig_p; - release_tree_vector (orig_args); - result = convert_from_reference (result); - } - - if (koenig_p) - { - /* Free garbage OVERLOADs from arg-dependent lookup. */ - tree next = NULL_TREE; - for (fn = orig_fn; - fn && TREE_CODE (fn) == OVERLOAD && OVL_ARG_DEPENDENT (fn); - fn = next) - { - if (processing_template_decl) - /* In a template, we'll re-use them at instantiation time. */ - OVL_ARG_DEPENDENT (fn) = false; - else - { - next = OVL_CHAIN (fn); - ggc_free (fn); - } - } - } - - 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 (input_location, code, expr, tf_warning_or_error); -} - -/* Finish a use of `this'. Returns an expression for `this'. */ - -tree -finish_this_expr (void) -{ - tree result; - - if (current_class_ptr) - { - tree type = TREE_TYPE (current_class_ref); - - /* In a lambda expression, 'this' refers to the captured 'this'. */ - if (LAMBDA_TYPE_P (type)) - result = lambda_expr_this_capture (CLASSTYPE_LAMBDA_EXPR (type)); - else - 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 (object == error_mark_node || 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 (location_t loc, enum tree_code code, tree expr, - tsubst_flags_t complain) -{ - tree result = build_x_unary_op (loc, code, expr, complain); - if ((complain & tf_warning) - && TREE_OVERFLOW_P (result) && !TREE_OVERFLOW_P (expr)) - overflow_warning (input_location, result); - - return result; -} - -/* Finish a compound-literal expression. TYPE is the type to which - the CONSTRUCTOR in COMPOUND_LITERAL is being cast. */ - -tree -finish_compound_literal (tree type, tree compound_literal, - tsubst_flags_t complain) -{ - if (type == error_mark_node) - return error_mark_node; - - if (TREE_CODE (type) == REFERENCE_TYPE) - { - compound_literal - = finish_compound_literal (TREE_TYPE (type), compound_literal, - complain); - return cp_build_c_cast (type, compound_literal, complain); - } - - if (!TYPE_OBJ_P (type)) - { - if (complain & tf_error) - error ("compound literal of non-object type %qT", type); - return error_mark_node; - } - - 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; - } - - type = complete_type (type); - - if (TYPE_NON_AGGREGATE_CLASS (type)) - { - /* Trying to deal with a CONSTRUCTOR instead of a TREE_LIST - everywhere that deals with function arguments would be a pain, so - just wrap it in a TREE_LIST. The parser set a flag so we know - that it came from T{} rather than T({}). */ - CONSTRUCTOR_IS_DIRECT_INIT (compound_literal) = 1; - compound_literal = build_tree_list (NULL_TREE, compound_literal); - return build_functional_cast (type, compound_literal, complain); - } - - if (TREE_CODE (type) == ARRAY_TYPE - && check_array_initializer (NULL_TREE, type, compound_literal)) - return error_mark_node; - compound_literal = reshape_init (type, compound_literal, complain); - if (SCALAR_TYPE_P (type) - && !BRACE_ENCLOSED_INITIALIZER_P (compound_literal) - && (complain & tf_warning_or_error)) - check_narrowing (type, compound_literal); - if (TREE_CODE (type) == ARRAY_TYPE - && TYPE_DOMAIN (type) == NULL_TREE) - { - cp_complete_array_type_or_error (&type, compound_literal, - false, complain); - if (type == error_mark_node) - return error_mark_node; - } - compound_literal = digest_init (type, compound_literal, complain); - if (TREE_CODE (compound_literal) == CONSTRUCTOR) - TREE_HAS_CONSTRUCTOR (compound_literal) = true; - /* Put static/constant array temporaries in static variables, but always - represent class temporaries with TARGET_EXPR so we elide copies. */ - if ((!at_function_scope_p () || CP_TYPE_CONST_P (type)) - && TREE_CODE (type) == ARRAY_TYPE - && !TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type) - && initializer_constant_valid_p (compound_literal, type)) - { - tree decl = create_temporary_var (type); - DECL_INITIAL (decl) = compound_literal; - TREE_STATIC (decl) = 1; - if (literal_type_p (type) && CP_TYPE_CONST_NON_VOLATILE_P (type)) - { - /* 5.19 says that a constant expression can include an - lvalue-rvalue conversion applied to "a glvalue of literal type - that refers to a non-volatile temporary object initialized - with a constant expression". Rather than try to communicate - that this VAR_DECL is a temporary, just mark it constexpr. */ - DECL_DECLARED_CONSTEXPR_P (decl) = true; - DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true; - TREE_CONSTANT (decl) = true; - } - cp_apply_type_quals_to_decl (cp_type_quals (type), decl); - decl = pushdecl_top_level (decl); - DECL_NAME (decl) = make_anon_name (); - SET_DECL_ASSEMBLER_NAME (decl, DECL_NAME (decl)); - return decl; - } - else - return get_target_expr_sfinae (compound_literal, complain); -} - -/* Return the declaration for the function-name variable indicated by - ID. */ - -tree -finish_fname (tree id) -{ - tree decl; - - decl = fname_decl (input_location, C_RID_CODE (id), id); - if (processing_template_decl && current_function_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) - { - permerror (input_location, "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 (input_location, - 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)); - - check_default_tmpl_args (decl, DECL_TEMPLATE_PARMS (tmpl), - /*is_primary=*/true, /*is_partial=*/false, - /*is_friend=*/0); - - 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) -{ - if (error_operand_p (t) || error_operand_p (TYPE_MAIN_DECL (t))) - return error_mark_node; - - if (processing_template_parmlist) - { - error ("definition of %q#T inside template parameter list", t); - return error_mark_node; - } - - /* According to the C++ ABI, decimal classes defined in ISO/IEC TR 24733 - are passed the same as decimal scalar types. */ - if (TREE_CODE (t) == RECORD_TYPE - && !processing_template_decl) - { - tree ns = TYPE_CONTEXT (t); - if (ns && TREE_CODE (ns) == NAMESPACE_DECL - && DECL_CONTEXT (ns) == std_node - && DECL_NAME (ns) - && !strcmp (IDENTIFIER_POINTER (DECL_NAME (ns)), "decimal")) - { - const char *n = TYPE_NAME_STRING (t); - if ((strcmp (n, "decimal32") == 0) - || (strcmp (n, "decimal64") == 0) - || (strcmp (n, "decimal128") == 0)) - TYPE_TRANSPARENT_AGGR (t) = 1; - } - } - - /* 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 || ! MAYBE_CLASS_TYPE_P (t)) - { - t = make_class_type (RECORD_TYPE); - pushtag (make_anon_name (), t, /*tag_scope=*/ts_current); - } - - if (TYPE_BEING_DEFINED (t)) - { - t = make_class_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; - - 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 (DECL_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, unless it's - a member of an enumeration. */ - if (TREE_CODE (decl) != CONST_DECL) - DECL_CONTEXT (decl) = current_class_type; - - /* Check for bare parameter packs in the member variable declaration. */ - if (TREE_CODE (decl) == FIELD_DECL) - { - if (check_for_bare_parameter_packs (TREE_TYPE (decl))) - TREE_TYPE (decl) = error_mark_node; - if (check_for_bare_parameter_packs (DECL_ATTRIBUTES (decl))) - DECL_ATTRIBUTES (decl) = NULL_TREE; - } - - /* [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)) - { - DECL_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 (pushdecl_class_level (decl)) - { - if (TREE_CODE (decl) == USING_DECL) - { - /* For now, ignore class-scope USING_DECLS, so that - debugging backends do not see them. */ - DECL_IGNORED_P (decl) = 1; - } - - /* 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 - { - DECL_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 type; - - type = lookup_template_class (name, args, - NULL_TREE, NULL_TREE, entering_scope, - tf_warning_or_error | tf_user); - if (type == error_mark_node) - return type; - else if (CLASS_TYPE_P (type) && !alias_type_or_template_p (type)) - return TYPE_STUB_DECL (type); - else - return TYPE_NAME (type); -} - -/* 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 (! MAYBE_CLASS_TYPE_P (base)) - { - error ("%qT is not a class type", base); - result = NULL_TREE; - } - else - { - if (cp_type_quals (base) != 0) - { - /* DR 484: Can a base-specifier name a cv-qualified - class type? */ - base = TYPE_MAIN_VARIANT (base); - } - result = build_tree_list (access, base); - if (virtual_p) - TREE_TYPE (result) = integer_type_node; - } - - return result; -} - -/* 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 scope; - tree cl; - - if (BASELINK_P (fns) - || error_operand_p (fns)) - return fns; - - scope = ovl_scope (fns); - if (!CLASS_TYPE_P (scope)) - return fns; - - cl = currently_open_derived_class (scope); - if (!cl) - cl = scope; - cl = TYPE_BINFO (cl); - return build_baselink (cl, cl, fns, /*optype=*/NULL_TREE); -} - -/* Returns true iff DECL is a variable from a function outside - the current one. */ - -static bool -outer_var_p (tree decl) -{ - return ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) - && DECL_FUNCTION_SCOPE_P (decl) - && DECL_CONTEXT (decl) != current_function_decl); -} - -/* As above, but also checks that DECL is automatic. */ - -static bool -outer_automatic_var_p (tree decl) -{ - return (outer_var_p (decl) - && !TREE_STATIC (decl)); -} - -/* 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, - location_t location) -{ - decl = strip_using_decl (decl); - - /* 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, location); - 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 - && TREE_CODE (id_expression) == IDENTIFIER_NODE) - maybe_note_name_used_in_class (id_expression, decl); - - /* Disallow uses of local variables from containing functions, except - within lambda-expressions. */ - if (!outer_var_p (decl) - /* It's not a use (3.2) if we're in an unevaluated context. */ - || cp_unevaluated_operand) - /* OK. */; - else if (TREE_STATIC (decl)) - { - if (processing_template_decl) - /* For a use of an outer static var, return the identifier so - that we'll look it up again in the instantiation. */ - return id_expression; - } - else - { - tree context = DECL_CONTEXT (decl); - tree containing_function = current_function_decl; - tree lambda_stack = NULL_TREE; - tree lambda_expr = NULL_TREE; - tree initializer = convert_from_reference (decl); - - /* Mark it as used now even if the use is ill-formed. */ - mark_used (decl); - - /* Core issue 696: "[At the July 2009 meeting] the CWG expressed - support for an approach in which a reference to a local - [constant] automatic variable in a nested class or lambda body - would enter the expression as an rvalue, which would reduce - the complexity of the problem" - - FIXME update for final resolution of core issue 696. */ - if (decl_constant_var_p (decl)) - { - if (processing_template_decl) - /* In a template, the constant value may not be in a usable - form, so look it up again at instantiation time. */ - return id_expression; - else - return integral_constant_value (decl); - } - - /* If we are in a lambda function, we can move out until we hit - 1. the context, - 2. a non-lambda function, or - 3. a non-default capturing lambda function. */ - while (context != containing_function - && LAMBDA_FUNCTION_P (containing_function)) - { - lambda_expr = CLASSTYPE_LAMBDA_EXPR - (DECL_CONTEXT (containing_function)); - - if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) - == CPLD_NONE) - break; - - lambda_stack = tree_cons (NULL_TREE, - lambda_expr, - lambda_stack); - - containing_function - = decl_function_context (containing_function); - } - - if (context == containing_function) - { - decl = add_default_capture (lambda_stack, - /*id=*/DECL_NAME (decl), - initializer); - } - else if (lambda_expr) - { - error ("%qD is not captured", decl); - return error_mark_node; - } - else - { - error (TREE_CODE (decl) == VAR_DECL - ? G_("use of local variable with automatic storage from containing function") - : G_("use of parameter from containing function")); - error (" %q+#D declared here", decl); - return error_mark_node; - } - } - - /* Also disallow uses of function parameters outside the function - body, except inside an unevaluated context (i.e. decltype). */ - if (TREE_CODE (decl) == PARM_DECL - && DECL_CONTEXT (decl) == NULL_TREE - && !cp_unevaluated_operand) - { - error ("use of parameter %qD outside function body", 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; - } - 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. */ - ; - else if (TREE_CODE (decl) == CONST_DECL) - /* We don't want to treat enumerators as dependent. */ - ; - /* A template-id where the name of the template was not resolved - is definitely dependent. */ - else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR - && (TREE_CODE (TREE_OPERAND (decl, 0)) - == IDENTIFIER_NODE)) - dependent_p = true; - /* For anything except an overloaded function, just check its - type. */ - else if (!is_overloaded_fn (decl)) - dependent_p - = dependent_type_p (TREE_TYPE (decl)); - /* For a set of overloaded functions, check each of the - functions. */ - else - { - tree fns = decl; - - if (BASELINK_P (fns)) - fns = BASELINK_FUNCTIONS (fns); - - /* For a template-id, check to see if the template - arguments are dependent. */ - if (TREE_CODE (fns) == TEMPLATE_ID_EXPR) - { - tree args = TREE_OPERAND (fns, 1); - dependent_p = any_dependent_template_arguments_p (args); - /* The functions are those referred to by the - template-id. */ - fns = TREE_OPERAND (fns, 0); - } - - /* If there are no dependent template arguments, go through - the overloaded functions. */ - while (fns && !dependent_p) - { - tree fn = OVL_CURRENT (fns); - - /* Member functions of dependent classes are - dependent. */ - if (TREE_CODE (fn) == FUNCTION_DECL - && type_dependent_expression_p (fn)) - dependent_p = true; - else if (TREE_CODE (fn) == TEMPLATE_DECL - && dependent_template_p (fn)) - dependent_p = true; - - fns = OVL_NEXT (fns); - } - } - - /* If the name was dependent on a template parameter, we will - resolve the name at instantiation time. */ - if (dependent_p) - { - /* Create a SCOPE_REF for qualified names, if the scope is - dependent. */ - if (scope) - { - if (TYPE_P (scope)) - { - if (address_p && done) - decl = finish_qualified_id_expr (scope, decl, - done, address_p, - template_p, - template_arg_p, - tf_warning_or_error); - else - { - tree type = NULL_TREE; - if (DECL_P (decl) && !dependent_scope_p (scope)) - type = TREE_TYPE (decl); - decl = build_qualified_name (type, - 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) - { - mark_used (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, NULL_TREE, - /*qualifying_scope=*/NULL_TREE); - pop_deferring_access_checks (); - return decl; - } - return id_expression; - } - - 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) == CONST_DECL - || TREE_CODE (decl) == RESULT_DECL) - && !mark_used (decl)) - return error_mark_node; - - /* Only certain kinds of names are allowed in constant - expression. Template parameters have already - been handled above. */ - if (! error_operand_p (decl) - && integral_constant_expression_p - && ! decl_constant_var_p (decl) - && TREE_CODE (decl) != CONST_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; - } - - tree wrap; - if (TREE_CODE (decl) == VAR_DECL - && !cp_unevaluated_operand - && DECL_THREAD_LOCAL_P (decl) - && (wrap = get_tls_wrapper_fn (decl))) - { - /* Replace an evaluated use of the thread_local variable with - a call to its wrapper. */ - decl = build_cxx_call (wrap, 0, NULL, tf_warning_or_error); - } - else if (scope) - { - decl = (adjust_result_of_qualified_name_lookup - (decl, scope, current_nonlambda_class_type())); - - if (TREE_CODE (decl) == FUNCTION_DECL) - mark_used (decl); - - if (TYPE_P (scope)) - decl = finish_qualified_id_expr (scope, - decl, - done, - address_p, - template_p, - template_arg_p, - tf_warning_or_error); - else - decl = convert_from_reference (decl); - } - 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, NULL_TREE, - /*qualifying_scope=*/NULL_TREE); - pop_deferring_access_checks (); - } - else if (is_overloaded_fn (decl)) - { - tree first_fn; - - first_fn = get_first_fn (decl); - if (TREE_CODE (first_fn) == TEMPLATE_DECL) - first_fn = DECL_TEMPLATE_RESULT (first_fn); - - if (!really_overloaded_fn (decl) - && !mark_used (first_fn)) - return error_mark_node; - - 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, - tf_warning_or_error); - } - - decl = baselink_for_fns (decl); - } - else - { - if (DECL_P (decl) && DECL_NONLOCAL (decl) - && DECL_CLASS_SCOPE_P (decl)) - { - tree context = context_for_name_lookup (decl); - if (context != current_class_type) - { - tree path = currently_open_derived_class (context); - perform_or_defer_access_check (TYPE_BINFO (path), - decl, decl, - tf_warning_or_error); - } - } - - decl = convert_from_reference (decl); - } - } - - if (TREE_DEPRECATED (decl)) - warn_deprecated_use (decl, NULL_TREE); - - 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 = cxx_make_type (TYPEOF_TYPE); - TYPEOF_TYPE_EXPR (type) = expr; - SET_TYPE_STRUCTURAL_EQUALITY (type); - - return type; - } - - expr = mark_type_use (expr); - - type = unlowered_expr_type (expr); - - if (!type || type == unknown_type_node) - { - error ("type of %qE is unknown", expr); - return error_mark_node; - } - - return type; -} - -/* Implement the __underlying_type keyword: Return the underlying - type of TYPE, suitable for use as a type-specifier. */ - -tree -finish_underlying_type (tree type) -{ - tree underlying_type; - - if (processing_template_decl) - { - underlying_type = cxx_make_type (UNDERLYING_TYPE); - UNDERLYING_TYPE_TYPE (underlying_type) = type; - SET_TYPE_STRUCTURAL_EQUALITY (underlying_type); - - return underlying_type; - } - - complete_type (type); - - if (TREE_CODE (type) != ENUMERAL_TYPE) - { - error ("%qT is not an enumeration type", type); - return error_mark_node; - } - - underlying_type = ENUM_UNDERLYING_TYPE (type); - - /* Fixup necessary in this case because ENUM_UNDERLYING_TYPE - includes TYPE_MIN_VALUE and TYPE_MAX_VALUE information. - See finish_enum_value_list for details. */ - if (!ENUM_FIXED_UNDERLYING_TYPE_P (type)) - underlying_type - = c_common_type_for_mode (TYPE_MODE (underlying_type), - TYPE_UNSIGNED (underlying_type)); - - return underlying_type; -} - -/* Implement the __direct_bases keyword: Return the direct base classes - of type */ - -tree -calculate_direct_bases (tree type) -{ - vec<tree, va_gc> *vector = make_tree_vector(); - tree bases_vec = NULL_TREE; - vec<tree, va_gc> *base_binfos; - tree binfo; - unsigned i; - - complete_type (type); - - if (!NON_UNION_CLASS_TYPE_P (type)) - return make_tree_vec (0); - - base_binfos = BINFO_BASE_BINFOS (TYPE_BINFO (type)); - - /* Virtual bases are initialized first */ - for (i = 0; base_binfos->iterate (i, &binfo); i++) - { - if (BINFO_VIRTUAL_P (binfo)) - { - vec_safe_push (vector, binfo); - } - } - - /* Now non-virtuals */ - for (i = 0; base_binfos->iterate (i, &binfo); i++) - { - if (!BINFO_VIRTUAL_P (binfo)) - { - vec_safe_push (vector, binfo); - } - } - - - bases_vec = make_tree_vec (vector->length ()); - - for (i = 0; i < vector->length (); ++i) - { - TREE_VEC_ELT (bases_vec, i) = BINFO_TYPE ((*vector)[i]); - } - return bases_vec; -} - -/* Implement the __bases keyword: Return the base classes - of type */ - -/* Find morally non-virtual base classes by walking binfo hierarchy */ -/* Virtual base classes are handled separately in finish_bases */ - -static tree -dfs_calculate_bases_pre (tree binfo, void * /*data_*/) -{ - /* Don't walk bases of virtual bases */ - return BINFO_VIRTUAL_P (binfo) ? dfs_skip_bases : NULL_TREE; -} - -static tree -dfs_calculate_bases_post (tree binfo, void *data_) -{ - vec<tree, va_gc> **data = ((vec<tree, va_gc> **) data_); - if (!BINFO_VIRTUAL_P (binfo)) - { - vec_safe_push (*data, BINFO_TYPE (binfo)); - } - return NULL_TREE; -} - -/* Calculates the morally non-virtual base classes of a class */ -static vec<tree, va_gc> * -calculate_bases_helper (tree type) -{ - vec<tree, va_gc> *vector = make_tree_vector(); - - /* Now add non-virtual base classes in order of construction */ - dfs_walk_all (TYPE_BINFO (type), - dfs_calculate_bases_pre, dfs_calculate_bases_post, &vector); - return vector; -} - -tree -calculate_bases (tree type) -{ - vec<tree, va_gc> *vector = make_tree_vector(); - tree bases_vec = NULL_TREE; - unsigned i; - vec<tree, va_gc> *vbases; - vec<tree, va_gc> *nonvbases; - tree binfo; - - complete_type (type); - - if (!NON_UNION_CLASS_TYPE_P (type)) - return make_tree_vec (0); - - /* First go through virtual base classes */ - for (vbases = CLASSTYPE_VBASECLASSES (type), i = 0; - vec_safe_iterate (vbases, i, &binfo); i++) - { - vec<tree, va_gc> *vbase_bases; - vbase_bases = calculate_bases_helper (BINFO_TYPE (binfo)); - vec_safe_splice (vector, vbase_bases); - release_tree_vector (vbase_bases); - } - - /* Now for the non-virtual bases */ - nonvbases = calculate_bases_helper (type); - vec_safe_splice (vector, nonvbases); - release_tree_vector (nonvbases); - - /* Last element is entire class, so don't copy */ - bases_vec = make_tree_vec (vector->length () - 1); - - for (i = 0; i < vector->length () - 1; ++i) - { - TREE_VEC_ELT (bases_vec, i) = (*vector)[i]; - } - release_tree_vector (vector); - return bases_vec; -} - -tree -finish_bases (tree type, bool direct) -{ - tree bases = NULL_TREE; - - if (!processing_template_decl) - { - /* Parameter packs can only be used in templates */ - error ("Parameter pack __bases only valid in template declaration"); - return error_mark_node; - } - - bases = cxx_make_type (BASES); - BASES_TYPE (bases) = type; - BASES_DIRECT (bases) = direct; - SET_TYPE_STRUCTURAL_EQUALITY (bases); - - return bases; -} - -/* 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_TYPE (expr) == unknown_type_node) - { - 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; - } - if (REFERENCE_REF_P (expr)) - expr = TREE_OPERAND (expr, 0); - if (TREE_CODE (expr) == COMPONENT_REF) - { - tree object = TREE_OPERAND (expr, 0); - if (!complete_type_or_else (TREE_TYPE (object), object)) - return error_mark_node; - } - return fold_offsetof (expr); -} - -/* 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 = AGGR_INIT_EXPR_FN (aggr_init_expr); - tree slot = AGGR_INIT_EXPR_SLOT (aggr_init_expr); - 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; - } - - call_expr = build_call_array_loc (input_location, - TREE_TYPE (TREE_TYPE (TREE_TYPE (fn))), - fn, - aggr_init_expr_nargs (aggr_init_expr), - AGGR_INIT_EXPR_ARGP (aggr_init_expr)); - TREE_NOTHROW (call_expr) = TREE_NOTHROW (aggr_init_expr); - - if (style == ctor) - { - /* Replace the first argument to the ctor with the address of the - slot. */ - cxx_mark_addressable (slot); - CALL_EXPR_ARG (call_expr, 0) = - build1 (ADDR_EXPR, build_pointer_type (type), slot); - } - else 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 (INIT_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, - tf_warning_or_error); - pop_deferring_access_checks (); - call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (slot), call_expr, slot); - } - - if (AGGR_INIT_ZERO_FIRST (aggr_init_expr)) - { - tree init = build_zero_init (type, NULL_TREE, - /*static_storage_p=*/false); - init = build2 (INIT_EXPR, void_type_node, slot, init); - call_expr = build2 (COMPOUND_EXPR, TREE_TYPE (call_expr), - init, call_expr); - } - - *tp = call_expr; -} - -/* Emit all thunks to FN that should be emitted when FN is emitted. */ - -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) - /* Do not emit thunks for extern template instantiations. */ - && ! DECL_REALLY_EXTERN (fn)) - { - tree thunk; - - for (thunk = DECL_THUNKS (fn); thunk; thunk = DECL_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 = DECL_CHAIN (probe)) - use_thunk (probe, /*emit_p=*/1); - } - } - else - gcc_assert (!DECL_THUNKS (thunk)); - } - } -} - -/* Returns true iff FUN is an instantiation of a constexpr function - template. */ - -static inline bool -is_instantiation_of_constexpr (tree fun) -{ - return (DECL_TEMPLOID_INSTANTIATION (fun) - && DECL_DECLARED_CONSTEXPR_P (DECL_TEMPLATE_RESULT - (DECL_TI_TEMPLATE (fun)))); -} - -/* Generate RTL for FN. */ - -bool -expand_or_defer_fn_1 (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 false; - } - - gcc_assert (DECL_SAVED_TREE (fn)); - - /* 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; - /* If this is an instantiation of a constexpr function, keep - DECL_SAVED_TREE for explain_invalid_constexpr_fn. */ - if (!is_instantiation_of_constexpr (fn)) - DECL_SAVED_TREE (fn) = NULL_TREE; - return false; - } - - /* 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. Similarly, all dllexport'd functions must - be emitted; there may be callers in other DLLs. */ - if ((flag_keep_inline_functions - && DECL_DECLARED_INLINE_P (fn) - && !DECL_REALLY_EXTERN (fn)) - || (flag_keep_inline_dllexport - && lookup_attribute ("dllexport", DECL_ATTRIBUTES (fn)))) - { - mark_needed (fn); - DECL_EXTERNAL (fn) = 0; - } - } - - /* 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 false; - - return true; -} - -void -expand_or_defer_fn (tree fn) -{ - if (expand_or_defer_fn_1 (fn)) - { - function_depth++; - - /* Expand or defer, at the whim of the compilation unit manager. */ - cgraph_finalize_function (fn, function_depth > 1); - emit_associated_thunks (fn); - - function_depth--; - } -} - -struct nrv_data -{ - tree var; - tree result; - hash_table <pointer_hash <tree_node> > 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; - tree_node **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)); - else - init = build_empty_stmt (EXPR_LOCATION (*tp)); - DECL_INITIAL (dp->var) = NULL_TREE; - SET_EXPR_LOCATION (init, EXPR_LOCATION (*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 = dp->visited.find_slot (*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 name from VAR to RESULT. */ - DECL_NAME (result) = DECL_NAME (var); - /* Don't forget that we take its address. */ - TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (var); - /* Finally set DECL_VALUE_EXPR to avoid assigning - a stack slot at -O0 for the original var and debug info - uses RESULT location for VAR. */ - SET_DECL_VALUE_EXPR (var, result); - DECL_HAS_VALUE_EXPR_P (var) = 1; - - data.var = var; - data.result = result; - data.visited.create (37); - cp_walk_tree (tp, finalize_nrv_r, &data, 0); - data.visited.dispose (); -} - -/* Create CP_OMP_CLAUSE_INFO for clause C. Returns true if it is invalid. */ - -bool -cxx_omp_create_clause_info (tree c, tree type, bool need_default_ctor, - bool need_copy_ctor, bool need_copy_assignment) -{ - int save_errorcount = errorcount; - tree info, t; - - /* 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) - { - if (need_default_ctor) - t = get_default_ctor (type); - else - t = get_copy_ctor (type, tf_warning_or_error); - - if (t && !trivial_fn_p (t)) - TREE_VEC_ELT (info, 0) = t; - } - - if ((need_default_ctor || need_copy_ctor) - && TYPE_HAS_NONTRIVIAL_DESTRUCTOR (type)) - TREE_VEC_ELT (info, 1) = get_dtor (type, tf_warning_or_error); - - if (need_copy_assignment) - { - t = get_copy_assign (type); - - if (t && !trivial_fn_p (t)) - TREE_VEC_ELT (info, 2) = t; - } - - return errorcount != save_errorcount; -} - -/* 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; - if (DECL_P (t)) - error ("%qD is not a variable in clause %<firstprivate%>", t); - else - 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 ("%qD 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; - if (DECL_P (t)) - error ("%qD is not a variable in clause %<lastprivate%>", t); - else - 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 ("%qD 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; - else if (!processing_template_decl) - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); - OMP_CLAUSE_IF_EXPR (c) = t; - break; - - case OMP_CLAUSE_FINAL: - t = OMP_CLAUSE_FINAL_EXPR (c); - t = maybe_convert_cond (t); - if (t == error_mark_node) - remove = true; - else if (!processing_template_decl) - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); - OMP_CLAUSE_FINAL_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 (!type_dependent_expression_p (t) - && !INTEGRAL_TYPE_P (TREE_TYPE (t))) - { - error ("num_threads expression must be integral"); - remove = true; - } - else - { - t = mark_rvalue_use (t); - if (!processing_template_decl) - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); - OMP_CLAUSE_NUM_THREADS_EXPR (c) = t; - } - 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 (!type_dependent_expression_p (t) - && !INTEGRAL_TYPE_P (TREE_TYPE (t))) - { - error ("schedule chunk size expression must be integral"); - remove = true; - } - else - { - t = mark_rvalue_use (t); - if (!processing_template_decl) - t = fold_build_cleanup_point_expr (TREE_TYPE (t), t); - OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t; - } - break; - - case OMP_CLAUSE_NOWAIT: - case OMP_CLAUSE_ORDERED: - case OMP_CLAUSE_DEFAULT: - case OMP_CLAUSE_UNTIED: - case OMP_CLAUSE_COLLAPSE: - case OMP_CLAUSE_MERGEABLE: - 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 omp_clause_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: - case MIN_EXPR: - case MAX_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 || need_copy_assignment) - { - t = require_complete_type (t); - if (t == error_mark_node) - remove = true; - else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE - && need_complete_non_reference) - { - 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: - /* const vars may be specified in firstprivate clause. */ - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE - && cxx_omp_const_qual_no_mutable (t)) - break; - 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) - && COMPLETE_TYPE_P (inner_type) - && (need_default_ctor || need_copy_ctor || need_copy_assignment) - && !type_dependent_expression_p (t) - && cxx_omp_create_clause_info (c, inner_type, need_default_ctor, - need_copy_ctor, need_copy_assignment)) - 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 (error_operand_p (v)) - ; - else if (TREE_CODE (v) != VAR_DECL) - error ("%<threadprivate%> %qD is not file, namespace " - "or block scope variable", v); - /* If V had already been marked threadprivate, it doesn't matter - whether it had been used prior to this point. */ - else 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 (complete_type (TREE_TYPE (v)))) - error ("%<threadprivate%> %qE has incomplete type", v); - else if (TREE_STATIC (v) && TYPE_P (CP_DECL_CONTEXT (v)) - && CP_DECL_CONTEXT (v) != current_class_type) - error ("%<threadprivate%> %qE directive not " - "in %qT definition", v, CP_DECL_CONTEXT (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)->u.base.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); -} - -tree -begin_omp_task (void) -{ - keep_next_level (true); - return begin_omp_structured_block (); -} - -tree -finish_omp_task (tree clauses, tree body) -{ - tree stmt; - - body = finish_omp_structured_block (body); - - stmt = make_node (OMP_TASK); - TREE_TYPE (stmt) = void_type_node; - OMP_TASK_CLAUSES (stmt) = clauses; - OMP_TASK_BODY (stmt) = body; - - return add_stmt (stmt); -} - -/* Helper function for finish_omp_for. Convert Ith random access iterator - into integral iterator. Return FALSE if successful. */ - -static bool -handle_omp_for_class_iterator (int i, location_t locus, tree declv, tree initv, - tree condv, tree incrv, tree *body, - tree *pre_body, tree clauses) -{ - tree diff, iter_init, iter_incr = NULL, last; - tree incr_var = NULL, orig_pre_body, orig_body, c; - tree decl = TREE_VEC_ELT (declv, i); - tree init = TREE_VEC_ELT (initv, i); - tree cond = TREE_VEC_ELT (condv, i); - tree incr = TREE_VEC_ELT (incrv, i); - tree iter = decl; - location_t elocus = locus; - - if (init && EXPR_HAS_LOCATION (init)) - elocus = EXPR_LOCATION (init); - - switch (TREE_CODE (cond)) - { - case GT_EXPR: - case GE_EXPR: - case LT_EXPR: - case LE_EXPR: - if (TREE_OPERAND (cond, 1) == iter) - cond = build2 (swap_tree_comparison (TREE_CODE (cond)), - TREE_TYPE (cond), iter, TREE_OPERAND (cond, 0)); - if (TREE_OPERAND (cond, 0) != iter) - cond = error_mark_node; - else - { - tree tem = build_x_binary_op (EXPR_LOCATION (cond), - TREE_CODE (cond), - iter, ERROR_MARK, - TREE_OPERAND (cond, 1), ERROR_MARK, - NULL, tf_warning_or_error); - if (error_operand_p (tem)) - return true; - } - break; - default: - cond = error_mark_node; - break; - } - if (cond == error_mark_node) - { - error_at (elocus, "invalid controlling predicate"); - return true; - } - diff = build_x_binary_op (elocus, MINUS_EXPR, TREE_OPERAND (cond, 1), - ERROR_MARK, iter, ERROR_MARK, NULL, - tf_warning_or_error); - if (error_operand_p (diff)) - return true; - if (TREE_CODE (TREE_TYPE (diff)) != INTEGER_TYPE) - { - error_at (elocus, "difference between %qE and %qD does not have integer type", - TREE_OPERAND (cond, 1), iter); - return true; - } - - switch (TREE_CODE (incr)) - { - case PREINCREMENT_EXPR: - case PREDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - if (TREE_OPERAND (incr, 0) != iter) - { - incr = error_mark_node; - break; - } - iter_incr = build_x_unary_op (EXPR_LOCATION (incr), - TREE_CODE (incr), iter, - tf_warning_or_error); - if (error_operand_p (iter_incr)) - return true; - else if (TREE_CODE (incr) == PREINCREMENT_EXPR - || TREE_CODE (incr) == POSTINCREMENT_EXPR) - incr = integer_one_node; - else - incr = integer_minus_one_node; - break; - case MODIFY_EXPR: - if (TREE_OPERAND (incr, 0) != iter) - incr = error_mark_node; - else if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR - || TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR) - { - tree rhs = TREE_OPERAND (incr, 1); - if (TREE_OPERAND (rhs, 0) == iter) - { - if (TREE_CODE (TREE_TYPE (TREE_OPERAND (rhs, 1))) - != INTEGER_TYPE) - incr = error_mark_node; - else - { - iter_incr = build_x_modify_expr (EXPR_LOCATION (rhs), - iter, TREE_CODE (rhs), - TREE_OPERAND (rhs, 1), - tf_warning_or_error); - if (error_operand_p (iter_incr)) - return true; - incr = TREE_OPERAND (rhs, 1); - incr = cp_convert (TREE_TYPE (diff), incr, - tf_warning_or_error); - if (TREE_CODE (rhs) == MINUS_EXPR) - { - incr = build1 (NEGATE_EXPR, TREE_TYPE (diff), incr); - incr = fold_if_not_in_template (incr); - } - if (TREE_CODE (incr) != INTEGER_CST - && (TREE_CODE (incr) != NOP_EXPR - || (TREE_CODE (TREE_OPERAND (incr, 0)) - != INTEGER_CST))) - iter_incr = NULL; - } - } - else if (TREE_OPERAND (rhs, 1) == iter) - { - if (TREE_CODE (TREE_TYPE (TREE_OPERAND (rhs, 0))) != INTEGER_TYPE - || TREE_CODE (rhs) != PLUS_EXPR) - incr = error_mark_node; - else - { - iter_incr = build_x_binary_op (EXPR_LOCATION (rhs), - PLUS_EXPR, - TREE_OPERAND (rhs, 0), - ERROR_MARK, iter, - ERROR_MARK, NULL, - tf_warning_or_error); - if (error_operand_p (iter_incr)) - return true; - iter_incr = build_x_modify_expr (EXPR_LOCATION (rhs), - iter, NOP_EXPR, - iter_incr, - tf_warning_or_error); - if (error_operand_p (iter_incr)) - return true; - incr = TREE_OPERAND (rhs, 0); - iter_incr = NULL; - } - } - else - incr = error_mark_node; - } - else - incr = error_mark_node; - break; - default: - incr = error_mark_node; - break; - } - - if (incr == error_mark_node) - { - error_at (elocus, "invalid increment expression"); - return true; - } - - incr = cp_convert (TREE_TYPE (diff), incr, tf_warning_or_error); - for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c)) - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE - && OMP_CLAUSE_DECL (c) == iter) - break; - - decl = create_temporary_var (TREE_TYPE (diff)); - pushdecl (decl); - add_decl_expr (decl); - last = create_temporary_var (TREE_TYPE (diff)); - pushdecl (last); - add_decl_expr (last); - if (c && iter_incr == NULL) - { - incr_var = create_temporary_var (TREE_TYPE (diff)); - pushdecl (incr_var); - add_decl_expr (incr_var); - } - gcc_assert (stmts_are_full_exprs_p ()); - - orig_pre_body = *pre_body; - *pre_body = push_stmt_list (); - if (orig_pre_body) - add_stmt (orig_pre_body); - if (init != NULL) - finish_expr_stmt (build_x_modify_expr (elocus, - iter, NOP_EXPR, init, - tf_warning_or_error)); - init = build_int_cst (TREE_TYPE (diff), 0); - if (c && iter_incr == NULL) - { - finish_expr_stmt (build_x_modify_expr (elocus, - incr_var, NOP_EXPR, - incr, tf_warning_or_error)); - incr = incr_var; - iter_incr = build_x_modify_expr (elocus, - iter, PLUS_EXPR, incr, - tf_warning_or_error); - } - finish_expr_stmt (build_x_modify_expr (elocus, - last, NOP_EXPR, init, - tf_warning_or_error)); - *pre_body = pop_stmt_list (*pre_body); - - cond = cp_build_binary_op (elocus, - TREE_CODE (cond), decl, diff, - tf_warning_or_error); - incr = build_modify_expr (elocus, decl, NULL_TREE, PLUS_EXPR, - elocus, incr, NULL_TREE); - - orig_body = *body; - *body = push_stmt_list (); - iter_init = build2 (MINUS_EXPR, TREE_TYPE (diff), decl, last); - iter_init = build_x_modify_expr (elocus, - iter, PLUS_EXPR, iter_init, - tf_warning_or_error); - iter_init = build1 (NOP_EXPR, void_type_node, iter_init); - finish_expr_stmt (iter_init); - finish_expr_stmt (build_x_modify_expr (elocus, - last, NOP_EXPR, decl, - tf_warning_or_error)); - add_stmt (orig_body); - *body = pop_stmt_list (*body); - - if (c) - { - OMP_CLAUSE_LASTPRIVATE_STMT (c) = push_stmt_list (); - finish_expr_stmt (iter_incr); - OMP_CLAUSE_LASTPRIVATE_STMT (c) - = pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (c)); - } - - TREE_VEC_ELT (declv, i) = decl; - TREE_VEC_ELT (initv, i) = init; - TREE_VEC_ELT (condv, i) = cond; - TREE_VEC_ELT (incrv, i) = incr; - - return false; -} - -/* 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 declv, tree initv, tree condv, - tree incrv, tree body, tree pre_body, tree clauses) -{ - tree omp_for = NULL, orig_incr = NULL; - tree decl, init, cond, incr; - location_t elocus; - int i; - - gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv)); - gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv)); - gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (incrv)); - for (i = 0; i < TREE_VEC_LENGTH (declv); i++) - { - decl = TREE_VEC_ELT (declv, i); - init = TREE_VEC_ELT (initv, i); - cond = TREE_VEC_ELT (condv, i); - incr = TREE_VEC_ELT (incrv, i); - elocus = locus; - - 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_at (locus, - "expected iteration declaration or initialization"); - return NULL; - } - } - - if (init && EXPR_HAS_LOCATION (init)) - elocus = EXPR_LOCATION (init); - - if (cond == NULL) - { - error_at (elocus, "missing controlling predicate"); - return NULL; - } - - if (incr == NULL) - { - error_at (elocus, "missing increment expression"); - return NULL; - } - - TREE_VEC_ELT (declv, i) = decl; - TREE_VEC_ELT (initv, i) = init; - } - - if (dependent_omp_for_p (declv, initv, condv, incrv)) - { - tree stmt; - - stmt = make_node (OMP_FOR); - - for (i = 0; i < TREE_VEC_LENGTH (declv); i++) - { - /* This is really just a place-holder. We'll be decomposing this - again and going through the cp_build_modify_expr path below when - we instantiate the thing. */ - TREE_VEC_ELT (initv, i) - = build2 (MODIFY_EXPR, void_type_node, TREE_VEC_ELT (declv, i), - TREE_VEC_ELT (initv, i)); - } - - TREE_TYPE (stmt) = void_type_node; - OMP_FOR_INIT (stmt) = initv; - OMP_FOR_COND (stmt) = condv; - OMP_FOR_INCR (stmt) = incrv; - OMP_FOR_BODY (stmt) = body; - OMP_FOR_PRE_BODY (stmt) = pre_body; - OMP_FOR_CLAUSES (stmt) = clauses; - - SET_EXPR_LOCATION (stmt, locus); - return add_stmt (stmt); - } - - if (processing_template_decl) - orig_incr = make_tree_vec (TREE_VEC_LENGTH (incrv)); - - for (i = 0; i < TREE_VEC_LENGTH (declv); ) - { - decl = TREE_VEC_ELT (declv, i); - init = TREE_VEC_ELT (initv, i); - cond = TREE_VEC_ELT (condv, i); - incr = TREE_VEC_ELT (incrv, i); - if (orig_incr) - TREE_VEC_ELT (orig_incr, i) = incr; - elocus = locus; - - if (init && EXPR_HAS_LOCATION (init)) - elocus = EXPR_LOCATION (init); - - if (!DECL_P (decl)) - { - error_at (elocus, "expected iteration declaration or initialization"); - return NULL; - } - - if (incr && TREE_CODE (incr) == MODOP_EXPR) - { - if (orig_incr) - TREE_VEC_ELT (orig_incr, i) = incr; - incr = cp_build_modify_expr (TREE_OPERAND (incr, 0), - TREE_CODE (TREE_OPERAND (incr, 1)), - TREE_OPERAND (incr, 2), - tf_warning_or_error); - } - - if (CLASS_TYPE_P (TREE_TYPE (decl))) - { - if (handle_omp_for_class_iterator (i, locus, declv, initv, condv, - incrv, &body, &pre_body, clauses)) - return NULL; - continue; - } - - if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)) - && TREE_CODE (TREE_TYPE (decl)) != POINTER_TYPE) - { - error_at (elocus, "invalid type for iteration variable %qE", decl); - return NULL; - } - - if (!processing_template_decl) - { - init = fold_build_cleanup_point_expr (TREE_TYPE (init), init); - init = cp_build_modify_expr (decl, NOP_EXPR, init, tf_warning_or_error); - } - else - init = build2 (MODIFY_EXPR, void_type_node, decl, init); - if (cond - && TREE_SIDE_EFFECTS (cond) - && COMPARISON_CLASS_P (cond) - && !processing_template_decl) - { - tree t = TREE_OPERAND (cond, 0); - if (TREE_SIDE_EFFECTS (t) - && t != decl - && (TREE_CODE (t) != NOP_EXPR - || TREE_OPERAND (t, 0) != decl)) - TREE_OPERAND (cond, 0) - = fold_build_cleanup_point_expr (TREE_TYPE (t), t); - - t = TREE_OPERAND (cond, 1); - if (TREE_SIDE_EFFECTS (t) - && t != decl - && (TREE_CODE (t) != NOP_EXPR - || TREE_OPERAND (t, 0) != decl)) - TREE_OPERAND (cond, 1) - = fold_build_cleanup_point_expr (TREE_TYPE (t), t); - } - if (decl == error_mark_node || init == error_mark_node) - return NULL; - - TREE_VEC_ELT (declv, i) = decl; - TREE_VEC_ELT (initv, i) = init; - TREE_VEC_ELT (condv, i) = cond; - TREE_VEC_ELT (incrv, i) = incr; - i++; - } - - if (IS_EMPTY_STMT (pre_body)) - pre_body = NULL; - - omp_for = c_finish_omp_for (locus, declv, initv, condv, incrv, - body, pre_body); - - if (omp_for == NULL) - return NULL; - - for (i = 0; i < TREE_VEC_LENGTH (OMP_FOR_INCR (omp_for)); i++) - { - decl = TREE_OPERAND (TREE_VEC_ELT (OMP_FOR_INIT (omp_for), i), 0); - incr = TREE_VEC_ELT (OMP_FOR_INCR (omp_for), i); - - if (TREE_CODE (incr) != MODIFY_EXPR) - continue; - - if (TREE_SIDE_EFFECTS (TREE_OPERAND (incr, 1)) - && BINARY_CLASS_P (TREE_OPERAND (incr, 1)) - && !processing_template_decl) - { - tree t = TREE_OPERAND (TREE_OPERAND (incr, 1), 0); - if (TREE_SIDE_EFFECTS (t) - && t != decl - && (TREE_CODE (t) != NOP_EXPR - || TREE_OPERAND (t, 0) != decl)) - TREE_OPERAND (TREE_OPERAND (incr, 1), 0) - = fold_build_cleanup_point_expr (TREE_TYPE (t), t); - - t = TREE_OPERAND (TREE_OPERAND (incr, 1), 1); - if (TREE_SIDE_EFFECTS (t) - && t != decl - && (TREE_CODE (t) != NOP_EXPR - || TREE_OPERAND (t, 0) != decl)) - TREE_OPERAND (TREE_OPERAND (incr, 1), 1) - = fold_build_cleanup_point_expr (TREE_TYPE (t), t); - } - - if (orig_incr) - TREE_VEC_ELT (OMP_FOR_INCR (omp_for), i) = TREE_VEC_ELT (orig_incr, i); - } - if (omp_for != NULL) - OMP_FOR_CLAUSES (omp_for) = clauses; - return omp_for; -} - -void -finish_omp_atomic (enum tree_code code, enum tree_code opcode, tree lhs, - tree rhs, tree v, tree lhs1, tree rhs1) -{ - tree orig_lhs; - tree orig_rhs; - tree orig_v; - tree orig_lhs1; - tree orig_rhs1; - bool dependent_p; - tree stmt; - - orig_lhs = lhs; - orig_rhs = rhs; - orig_v = v; - orig_lhs1 = lhs1; - orig_rhs1 = rhs1; - 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) - || (rhs && type_dependent_expression_p (rhs)) - || (v && type_dependent_expression_p (v)) - || (lhs1 && type_dependent_expression_p (lhs1)) - || (rhs1 && type_dependent_expression_p (rhs1))); - if (!dependent_p) - { - lhs = build_non_dependent_expr (lhs); - if (rhs) - rhs = build_non_dependent_expr (rhs); - if (v) - v = build_non_dependent_expr (v); - if (lhs1) - lhs1 = build_non_dependent_expr (lhs1); - if (rhs1) - rhs1 = build_non_dependent_expr (rhs1); - } - } - if (!dependent_p) - { - stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs, - v, lhs1, rhs1); - if (stmt == error_mark_node) - return; - } - if (processing_template_decl) - { - if (code == OMP_ATOMIC_READ) - { - stmt = build_min_nt_loc (EXPR_LOCATION (orig_lhs), - OMP_ATOMIC_READ, orig_lhs); - stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt); - } - else - { - if (opcode == NOP_EXPR) - stmt = build2 (MODIFY_EXPR, void_type_node, orig_lhs, orig_rhs); - else - stmt = build2 (opcode, void_type_node, orig_lhs, orig_rhs); - if (orig_rhs1) - stmt = build_min_nt_loc (EXPR_LOCATION (orig_rhs1), - COMPOUND_EXPR, orig_rhs1, stmt); - if (code != OMP_ATOMIC) - { - stmt = build_min_nt_loc (EXPR_LOCATION (orig_lhs1), - code, orig_lhs1, stmt); - stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt); - } - } - stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node, stmt); - } - add_stmt (stmt); -} - -void -finish_omp_barrier (void) -{ - tree fn = builtin_decl_explicit (BUILT_IN_GOMP_BARRIER); - vec<tree, va_gc> *vec = make_tree_vector (); - tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); - release_tree_vector (vec); - finish_expr_stmt (stmt); -} - -void -finish_omp_flush (void) -{ - tree fn = builtin_decl_explicit (BUILT_IN_SYNC_SYNCHRONIZE); - vec<tree, va_gc> *vec = make_tree_vector (); - tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); - release_tree_vector (vec); - finish_expr_stmt (stmt); -} - -void -finish_omp_taskwait (void) -{ - tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKWAIT); - vec<tree, va_gc> *vec = make_tree_vector (); - tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); - release_tree_vector (vec); - finish_expr_stmt (stmt); -} - -void -finish_omp_taskyield (void) -{ - tree fn = builtin_decl_explicit (BUILT_IN_GOMP_TASKYIELD); - vec<tree, va_gc> *vec = make_tree_vector (); - tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error); - release_tree_vector (vec); - finish_expr_stmt (stmt); -} - -/* Begin a __transaction_atomic or __transaction_relaxed statement. - If PCOMPOUND is non-null, this is for a function-transaction-block, and we - should create an extra compound stmt. */ - -tree -begin_transaction_stmt (location_t loc, tree *pcompound, int flags) -{ - tree r; - - if (pcompound) - *pcompound = begin_compound_stmt (0); - - r = build_stmt (loc, TRANSACTION_EXPR, NULL_TREE); - - /* Only add the statement to the function if support enabled. */ - if (flag_tm) - add_stmt (r); - else - error_at (loc, ((flags & TM_STMT_ATTR_RELAXED) != 0 - ? G_("%<__transaction_relaxed%> without " - "transactional memory support enabled") - : G_("%<__transaction_atomic%> without " - "transactional memory support enabled"))); - - TRANSACTION_EXPR_BODY (r) = push_stmt_list (); - TREE_SIDE_EFFECTS (r) = 1; - return r; -} - -/* End a __transaction_atomic or __transaction_relaxed statement. - If COMPOUND_STMT is non-null, this is for a function-transaction-block, - and we should end the compound. If NOEX is non-NULL, we wrap the body in - a MUST_NOT_THROW_EXPR with NOEX as condition. */ - -void -finish_transaction_stmt (tree stmt, tree compound_stmt, int flags, tree noex) -{ - TRANSACTION_EXPR_BODY (stmt) = pop_stmt_list (TRANSACTION_EXPR_BODY (stmt)); - TRANSACTION_EXPR_OUTER (stmt) = (flags & TM_STMT_ATTR_OUTER) != 0; - TRANSACTION_EXPR_RELAXED (stmt) = (flags & TM_STMT_ATTR_RELAXED) != 0; - TRANSACTION_EXPR_IS_STMT (stmt) = 1; - - /* noexcept specifications are not allowed for function transactions. */ - gcc_assert (!(noex && compound_stmt)); - if (noex) - { - tree body = build_must_not_throw_expr (TRANSACTION_EXPR_BODY (stmt), - noex); - SET_EXPR_LOCATION (body, EXPR_LOCATION (TRANSACTION_EXPR_BODY (stmt))); - TREE_SIDE_EFFECTS (body) = 1; - TRANSACTION_EXPR_BODY (stmt) = body; - } - - if (compound_stmt) - finish_compound_stmt (compound_stmt); - finish_stmt (); -} - -/* Build a __transaction_atomic or __transaction_relaxed expression. If - NOEX is non-NULL, we wrap the body in a MUST_NOT_THROW_EXPR with NOEX as - condition. */ - -tree -build_transaction_expr (location_t loc, tree expr, int flags, tree noex) -{ - tree ret; - if (noex) - { - expr = build_must_not_throw_expr (expr, noex); - SET_EXPR_LOCATION (expr, loc); - TREE_SIDE_EFFECTS (expr) = 1; - } - ret = build1 (TRANSACTION_EXPR, TREE_TYPE (expr), expr); - if (flags & TM_STMT_ATTR_RELAXED) - TRANSACTION_EXPR_RELAXED (ret) = 1; - TREE_SIDE_EFFECTS (ret) = 1; - SET_EXPR_LOCATION (ret, loc); - return ret; -} - -void -init_cp_semantics (void) -{ -} - -/* Build a STATIC_ASSERT for a static assertion with the condition - CONDITION and the message text MESSAGE. LOCATION is the location - of the static assertion in the source code. When MEMBER_P, this - static assertion is a member of a class. */ -void -finish_static_assert (tree condition, tree message, location_t location, - bool member_p) -{ - if (message == NULL_TREE - || message == error_mark_node - || condition == NULL_TREE - || condition == error_mark_node) - return; - - if (check_for_bare_parameter_packs (condition)) - condition = error_mark_node; - - if (type_dependent_expression_p (condition) - || value_dependent_expression_p (condition)) - { - /* We're in a template; build a STATIC_ASSERT and put it in - the right place. */ - tree assertion; - - assertion = make_node (STATIC_ASSERT); - STATIC_ASSERT_CONDITION (assertion) = condition; - STATIC_ASSERT_MESSAGE (assertion) = message; - STATIC_ASSERT_SOURCE_LOCATION (assertion) = location; - - if (member_p) - maybe_add_class_template_decl_list (current_class_type, - assertion, - /*friend_p=*/0); - else - add_stmt (assertion); - - return; - } - - /* Fold the expression and convert it to a boolean value. */ - condition = fold_non_dependent_expr (condition); - condition = cp_convert (boolean_type_node, condition, tf_warning_or_error); - condition = maybe_constant_value (condition); - - if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition)) - /* Do nothing; the condition is satisfied. */ - ; - else - { - location_t saved_loc = input_location; - - input_location = location; - if (TREE_CODE (condition) == INTEGER_CST - && integer_zerop (condition)) - /* Report the error. */ - error ("static assertion failed: %s", TREE_STRING_POINTER (message)); - else if (condition && condition != error_mark_node) - { - error ("non-constant condition for static assertion"); - cxx_constant_value (condition); - } - input_location = saved_loc; - } -} - -/* Implements the C++0x decltype keyword. Returns the type of EXPR, - suitable for use as a type-specifier. - - ID_EXPRESSION_OR_MEMBER_ACCESS_P is true when EXPR was parsed as an - id-expression or a class member access, FALSE when it was parsed as - a full expression. */ - -tree -finish_decltype_type (tree expr, bool id_expression_or_member_access_p, - tsubst_flags_t complain) -{ - tree type = NULL_TREE; - - if (!expr || error_operand_p (expr)) - return error_mark_node; - - if (TYPE_P (expr) - || TREE_CODE (expr) == TYPE_DECL - || (TREE_CODE (expr) == BIT_NOT_EXPR - && TYPE_P (TREE_OPERAND (expr, 0)))) - { - if (complain & tf_error) - error ("argument to decltype must be an expression"); - return error_mark_node; - } - - /* Depending on the resolution of DR 1172, we may later need to distinguish - instantiation-dependent but not type-dependent expressions so that, say, - A<decltype(sizeof(T))>::U doesn't require 'typename'. */ - if (instantiation_dependent_expression_p (expr)) - { - type = cxx_make_type (DECLTYPE_TYPE); - DECLTYPE_TYPE_EXPR (type) = expr; - DECLTYPE_TYPE_ID_EXPR_OR_MEMBER_ACCESS_P (type) - = id_expression_or_member_access_p; - SET_TYPE_STRUCTURAL_EQUALITY (type); - - return type; - } - - /* The type denoted by decltype(e) is defined as follows: */ - - expr = resolve_nondeduced_context (expr); - - if (type_unknown_p (expr)) - { - if (complain & tf_error) - error ("decltype cannot resolve address of overloaded function"); - return error_mark_node; - } - - if (invalid_nonstatic_memfn_p (expr, complain)) - return error_mark_node; - - /* To get the size of a static data member declared as an array of - unknown bound, we need to instantiate it. */ - if (TREE_CODE (expr) == VAR_DECL - && VAR_HAD_UNKNOWN_BOUND (expr) - && DECL_TEMPLATE_INSTANTIATION (expr)) - instantiate_decl (expr, /*defer_ok*/true, /*expl_inst_mem*/false); - - if (id_expression_or_member_access_p) - { - /* If e is an id-expression or a class member access (5.2.5 - [expr.ref]), decltype(e) is defined as the type of the entity - named by e. If there is no such entity, or e names a set of - overloaded functions, the program is ill-formed. */ - if (TREE_CODE (expr) == IDENTIFIER_NODE) - expr = lookup_name (expr); - - if (TREE_CODE (expr) == INDIRECT_REF) - /* This can happen when the expression is, e.g., "a.b". Just - look at the underlying operand. */ - expr = TREE_OPERAND (expr, 0); - - if (TREE_CODE (expr) == OFFSET_REF - || TREE_CODE (expr) == MEMBER_REF - || TREE_CODE (expr) == SCOPE_REF) - /* We're only interested in the field itself. If it is a - BASELINK, we will need to see through it in the next - step. */ - expr = TREE_OPERAND (expr, 1); - - if (BASELINK_P (expr)) - /* See through BASELINK nodes to the underlying function. */ - expr = BASELINK_FUNCTIONS (expr); - - switch (TREE_CODE (expr)) - { - case FIELD_DECL: - if (DECL_BIT_FIELD_TYPE (expr)) - { - type = DECL_BIT_FIELD_TYPE (expr); - break; - } - /* Fall through for fields that aren't bitfields. */ - - case FUNCTION_DECL: - case VAR_DECL: - case CONST_DECL: - case PARM_DECL: - case RESULT_DECL: - case TEMPLATE_PARM_INDEX: - expr = mark_type_use (expr); - type = TREE_TYPE (expr); - break; - - case ERROR_MARK: - type = error_mark_node; - break; - - case COMPONENT_REF: - case COMPOUND_EXPR: - mark_type_use (expr); - type = is_bitfield_expr_with_lowered_type (expr); - if (!type) - type = TREE_TYPE (TREE_OPERAND (expr, 1)); - break; - - case BIT_FIELD_REF: - gcc_unreachable (); - - case INTEGER_CST: - case PTRMEM_CST: - /* We can get here when the id-expression refers to an - enumerator or non-type template parameter. */ - type = TREE_TYPE (expr); - break; - - default: - /* Handle instantiated template non-type arguments. */ - type = TREE_TYPE (expr); - break; - } - } - else - { - /* Within a lambda-expression: - - Every occurrence of decltype((x)) where x is a possibly - parenthesized id-expression that names an entity of - automatic storage duration is treated as if x were - transformed into an access to a corresponding data member - of the closure type that would have been declared if x - were a use of the denoted entity. */ - if (outer_automatic_var_p (expr) - && current_function_decl - && LAMBDA_FUNCTION_P (current_function_decl)) - type = capture_decltype (expr); - else if (error_operand_p (expr)) - type = error_mark_node; - else if (expr == current_class_ptr) - /* If the expression is just "this", we want the - cv-unqualified pointer for the "this" type. */ - type = TYPE_MAIN_VARIANT (TREE_TYPE (expr)); - else - { - /* Otherwise, where T is the type of e, if e is an lvalue, - decltype(e) is defined as T&; if an xvalue, T&&; otherwise, T. */ - cp_lvalue_kind clk = lvalue_kind (expr); - type = unlowered_expr_type (expr); - gcc_assert (TREE_CODE (type) != REFERENCE_TYPE); - - /* For vector types, pick a non-opaque variant. */ - if (TREE_CODE (type) == VECTOR_TYPE) - type = strip_typedefs (type); - - if (clk != clk_none && !(clk & clk_class)) - type = cp_build_reference_type (type, (clk & clk_rvalueref)); - } - } - - return type; -} - -/* Called from trait_expr_value to evaluate either __has_nothrow_assign or - __has_nothrow_copy, depending on assign_p. */ - -static bool -classtype_has_nothrow_assign_or_copy_p (tree type, bool assign_p) -{ - tree fns; - - if (assign_p) - { - int ix; - ix = lookup_fnfields_1 (type, ansi_assopname (NOP_EXPR)); - if (ix < 0) - return false; - fns = (*CLASSTYPE_METHOD_VEC (type))[ix]; - } - else if (TYPE_HAS_COPY_CTOR (type)) - { - /* If construction of the copy constructor was postponed, create - it now. */ - if (CLASSTYPE_LAZY_COPY_CTOR (type)) - lazily_declare_fn (sfk_copy_constructor, type); - if (CLASSTYPE_LAZY_MOVE_CTOR (type)) - lazily_declare_fn (sfk_move_constructor, type); - fns = CLASSTYPE_CONSTRUCTORS (type); - } - else - return false; - - for (; fns; fns = OVL_NEXT (fns)) - { - tree fn = OVL_CURRENT (fns); - - if (assign_p) - { - if (copy_fn_p (fn) == 0) - continue; - } - else if (copy_fn_p (fn) <= 0) - continue; - - maybe_instantiate_noexcept (fn); - if (!TYPE_NOTHROW_P (TREE_TYPE (fn))) - return false; - } - - return true; -} - -/* Actually evaluates the trait. */ - -static bool -trait_expr_value (cp_trait_kind kind, tree type1, tree type2) -{ - enum tree_code type_code1; - tree t; - - type_code1 = TREE_CODE (type1); - - switch (kind) - { - case CPTK_HAS_NOTHROW_ASSIGN: - type1 = strip_array_types (type1); - return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE - && (trait_expr_value (CPTK_HAS_TRIVIAL_ASSIGN, type1, type2) - || (CLASS_TYPE_P (type1) - && classtype_has_nothrow_assign_or_copy_p (type1, - true)))); - - case CPTK_HAS_TRIVIAL_ASSIGN: - /* ??? The standard seems to be missing the "or array of such a class - type" wording for this trait. */ - type1 = strip_array_types (type1); - return (!CP_TYPE_CONST_P (type1) && type_code1 != REFERENCE_TYPE - && (trivial_type_p (type1) - || (CLASS_TYPE_P (type1) - && TYPE_HAS_TRIVIAL_COPY_ASSIGN (type1)))); - - case CPTK_HAS_NOTHROW_CONSTRUCTOR: - type1 = strip_array_types (type1); - return (trait_expr_value (CPTK_HAS_TRIVIAL_CONSTRUCTOR, type1, type2) - || (CLASS_TYPE_P (type1) - && (t = locate_ctor (type1)) - && (maybe_instantiate_noexcept (t), - TYPE_NOTHROW_P (TREE_TYPE (t))))); - - case CPTK_HAS_TRIVIAL_CONSTRUCTOR: - type1 = strip_array_types (type1); - return (trivial_type_p (type1) - || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_DFLT (type1))); - - case CPTK_HAS_NOTHROW_COPY: - type1 = strip_array_types (type1); - return (trait_expr_value (CPTK_HAS_TRIVIAL_COPY, type1, type2) - || (CLASS_TYPE_P (type1) - && classtype_has_nothrow_assign_or_copy_p (type1, false))); - - case CPTK_HAS_TRIVIAL_COPY: - /* ??? The standard seems to be missing the "or array of such a class - type" wording for this trait. */ - type1 = strip_array_types (type1); - return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE - || (CLASS_TYPE_P (type1) && TYPE_HAS_TRIVIAL_COPY_CTOR (type1))); - - case CPTK_HAS_TRIVIAL_DESTRUCTOR: - type1 = strip_array_types (type1); - return (trivial_type_p (type1) || type_code1 == REFERENCE_TYPE - || (CLASS_TYPE_P (type1) - && TYPE_HAS_TRIVIAL_DESTRUCTOR (type1))); - - case CPTK_HAS_VIRTUAL_DESTRUCTOR: - return type_has_virtual_destructor (type1); - - case CPTK_IS_ABSTRACT: - return (ABSTRACT_CLASS_TYPE_P (type1)); - - case CPTK_IS_BASE_OF: - return (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2) - && DERIVED_FROM_P (type1, type2)); - - case CPTK_IS_CLASS: - return (NON_UNION_CLASS_TYPE_P (type1)); - - case CPTK_IS_CONVERTIBLE_TO: - /* TODO */ - return false; - - case CPTK_IS_EMPTY: - return (NON_UNION_CLASS_TYPE_P (type1) && CLASSTYPE_EMPTY_P (type1)); - - case CPTK_IS_ENUM: - return (type_code1 == ENUMERAL_TYPE); - - case CPTK_IS_FINAL: - return (CLASS_TYPE_P (type1) && CLASSTYPE_FINAL (type1)); - - case CPTK_IS_LITERAL_TYPE: - return (literal_type_p (type1)); - - case CPTK_IS_POD: - return (pod_type_p (type1)); - - case CPTK_IS_POLYMORPHIC: - return (CLASS_TYPE_P (type1) && TYPE_POLYMORPHIC_P (type1)); - - case CPTK_IS_STD_LAYOUT: - return (std_layout_type_p (type1)); - - case CPTK_IS_TRIVIAL: - return (trivial_type_p (type1)); - - case CPTK_IS_UNION: - return (type_code1 == UNION_TYPE); - - default: - gcc_unreachable (); - return false; - } -} - -/* If TYPE is an array of unknown bound, or (possibly cv-qualified) - void, or a complete type, returns it, otherwise NULL_TREE. */ - -static tree -check_trait_type (tree type) -{ - if (TREE_CODE (type) == ARRAY_TYPE && !TYPE_DOMAIN (type) - && COMPLETE_TYPE_P (TREE_TYPE (type))) - return type; - - if (VOID_TYPE_P (type)) - return type; - - return complete_type_or_else (strip_array_types (type), NULL_TREE); -} - -/* Process a trait expression. */ - -tree -finish_trait_expr (cp_trait_kind kind, tree type1, tree type2) -{ - gcc_assert (kind == CPTK_HAS_NOTHROW_ASSIGN - || kind == CPTK_HAS_NOTHROW_CONSTRUCTOR - || kind == CPTK_HAS_NOTHROW_COPY - || kind == CPTK_HAS_TRIVIAL_ASSIGN - || kind == CPTK_HAS_TRIVIAL_CONSTRUCTOR - || kind == CPTK_HAS_TRIVIAL_COPY - || kind == CPTK_HAS_TRIVIAL_DESTRUCTOR - || kind == CPTK_HAS_VIRTUAL_DESTRUCTOR - || kind == CPTK_IS_ABSTRACT - || kind == CPTK_IS_BASE_OF - || kind == CPTK_IS_CLASS - || kind == CPTK_IS_CONVERTIBLE_TO - || kind == CPTK_IS_EMPTY - || kind == CPTK_IS_ENUM - || kind == CPTK_IS_FINAL - || kind == CPTK_IS_LITERAL_TYPE - || kind == CPTK_IS_POD - || kind == CPTK_IS_POLYMORPHIC - || kind == CPTK_IS_STD_LAYOUT - || kind == CPTK_IS_TRIVIAL - || kind == CPTK_IS_UNION); - - if (kind == CPTK_IS_CONVERTIBLE_TO) - { - sorry ("__is_convertible_to"); - return error_mark_node; - } - - if (type1 == error_mark_node - || ((kind == CPTK_IS_BASE_OF || kind == CPTK_IS_CONVERTIBLE_TO) - && type2 == error_mark_node)) - return error_mark_node; - - if (processing_template_decl) - { - tree trait_expr = make_node (TRAIT_EXPR); - TREE_TYPE (trait_expr) = boolean_type_node; - TRAIT_EXPR_TYPE1 (trait_expr) = type1; - TRAIT_EXPR_TYPE2 (trait_expr) = type2; - TRAIT_EXPR_KIND (trait_expr) = kind; - return trait_expr; - } - - switch (kind) - { - case CPTK_HAS_NOTHROW_ASSIGN: - case CPTK_HAS_TRIVIAL_ASSIGN: - case CPTK_HAS_NOTHROW_CONSTRUCTOR: - case CPTK_HAS_TRIVIAL_CONSTRUCTOR: - case CPTK_HAS_NOTHROW_COPY: - case CPTK_HAS_TRIVIAL_COPY: - case CPTK_HAS_TRIVIAL_DESTRUCTOR: - case CPTK_HAS_VIRTUAL_DESTRUCTOR: - case CPTK_IS_ABSTRACT: - case CPTK_IS_EMPTY: - case CPTK_IS_FINAL: - case CPTK_IS_LITERAL_TYPE: - case CPTK_IS_POD: - case CPTK_IS_POLYMORPHIC: - case CPTK_IS_STD_LAYOUT: - case CPTK_IS_TRIVIAL: - if (!check_trait_type (type1)) - return error_mark_node; - break; - - case CPTK_IS_BASE_OF: - if (NON_UNION_CLASS_TYPE_P (type1) && NON_UNION_CLASS_TYPE_P (type2) - && !same_type_ignoring_top_level_qualifiers_p (type1, type2) - && !complete_type_or_else (type2, NULL_TREE)) - /* We already issued an error. */ - return error_mark_node; - break; - - case CPTK_IS_CLASS: - case CPTK_IS_ENUM: - case CPTK_IS_UNION: - break; - - case CPTK_IS_CONVERTIBLE_TO: - default: - gcc_unreachable (); - } - - return (trait_expr_value (kind, type1, type2) - ? boolean_true_node : boolean_false_node); -} - -/* Do-nothing variants of functions to handle pragma FLOAT_CONST_DECIMAL64, - which is ignored for C++. */ - -void -set_float_const_decimal64 (void) -{ -} - -void -clear_float_const_decimal64 (void) -{ -} - -bool -float_const_decimal64_p (void) -{ - return 0; -} - - -/* Return true if T is a literal type. */ - -bool -literal_type_p (tree t) -{ - if (SCALAR_TYPE_P (t) - || TREE_CODE (t) == VECTOR_TYPE - || TREE_CODE (t) == REFERENCE_TYPE) - return true; - if (CLASS_TYPE_P (t)) - { - t = complete_type (t); - gcc_assert (COMPLETE_TYPE_P (t) || errorcount); - return CLASSTYPE_LITERAL_P (t); - } - if (TREE_CODE (t) == ARRAY_TYPE) - return literal_type_p (strip_array_types (t)); - return false; -} - -/* If DECL is a variable declared `constexpr', require its type - be literal. Return the DECL if OK, otherwise NULL. */ - -tree -ensure_literal_type_for_constexpr_object (tree decl) -{ - tree type = TREE_TYPE (decl); - if (TREE_CODE (decl) == VAR_DECL && DECL_DECLARED_CONSTEXPR_P (decl) - && !processing_template_decl) - { - if (CLASS_TYPE_P (type) && !COMPLETE_TYPE_P (complete_type (type))) - /* Don't complain here, we'll complain about incompleteness - when we try to initialize the variable. */; - else if (!literal_type_p (type)) - { - error ("the type %qT of constexpr variable %qD is not literal", - type, decl); - explain_non_literal_class (type); - return NULL; - } - } - return decl; -} - -/* Representation of entries in the constexpr function definition table. */ - -typedef struct GTY(()) constexpr_fundef { - tree decl; - tree body; -} constexpr_fundef; - -/* This table holds all constexpr function definitions seen in - the current translation unit. */ - -static GTY ((param_is (constexpr_fundef))) htab_t constexpr_fundef_table; - -/* Utility function used for managing the constexpr function table. - Return true if the entries pointed to by P and Q are for the - same constexpr function. */ - -static inline int -constexpr_fundef_equal (const void *p, const void *q) -{ - const constexpr_fundef *lhs = (const constexpr_fundef *) p; - const constexpr_fundef *rhs = (const constexpr_fundef *) q; - return lhs->decl == rhs->decl; -} - -/* Utility function used for managing the constexpr function table. - Return a hash value for the entry pointed to by Q. */ - -static inline hashval_t -constexpr_fundef_hash (const void *p) -{ - const constexpr_fundef *fundef = (const constexpr_fundef *) p; - return DECL_UID (fundef->decl); -} - -/* Return a previously saved definition of function FUN. */ - -static constexpr_fundef * -retrieve_constexpr_fundef (tree fun) -{ - constexpr_fundef fundef = { NULL, NULL }; - if (constexpr_fundef_table == NULL) - return NULL; - - fundef.decl = fun; - return (constexpr_fundef *) htab_find (constexpr_fundef_table, &fundef); -} - -/* Check whether the parameter and return types of FUN are valid for a - constexpr function, and complain if COMPLAIN. */ - -static bool -is_valid_constexpr_fn (tree fun, bool complain) -{ - tree parm = FUNCTION_FIRST_USER_PARM (fun); - bool ret = true; - for (; parm != NULL; parm = TREE_CHAIN (parm)) - if (!literal_type_p (TREE_TYPE (parm))) - { - ret = false; - if (complain) - { - error ("invalid type for parameter %d of constexpr " - "function %q+#D", DECL_PARM_INDEX (parm), fun); - explain_non_literal_class (TREE_TYPE (parm)); - } - } - - if (!DECL_CONSTRUCTOR_P (fun)) - { - tree rettype = TREE_TYPE (TREE_TYPE (fun)); - if (!literal_type_p (rettype)) - { - ret = false; - if (complain) - { - error ("invalid return type %qT of constexpr function %q+D", - rettype, fun); - explain_non_literal_class (rettype); - } - } - - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) - && !CLASSTYPE_LITERAL_P (DECL_CONTEXT (fun))) - { - ret = false; - if (complain) - { - error ("enclosing class of constexpr non-static member " - "function %q+#D is not a literal type", fun); - explain_non_literal_class (DECL_CONTEXT (fun)); - } - } - } - else if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fun))) - { - ret = false; - if (complain) - error ("%q#T has virtual base classes", DECL_CONTEXT (fun)); - } - - return ret; -} - -/* Subroutine of build_data_member_initialization. MEMBER is a COMPONENT_REF - for a member of an anonymous aggregate, INIT is the initializer for that - member, and VEC_OUTER is the vector of constructor elements for the class - whose constructor we are processing. Add the initializer to the vector - and return true to indicate success. */ - -static bool -build_anon_member_initialization (tree member, tree init, - vec<constructor_elt, va_gc> **vec_outer) -{ - /* MEMBER presents the relevant fields from the inside out, but we need - to build up the initializer from the outside in so that we can reuse - previously built CONSTRUCTORs if this is, say, the second field in an - anonymous struct. So we use a vec as a stack. */ - vec<tree> fields; - fields.create (2); - do - { - fields.safe_push (TREE_OPERAND (member, 1)); - member = TREE_OPERAND (member, 0); - } - while (ANON_AGGR_TYPE_P (TREE_TYPE (member))); - - /* VEC has the constructor elements vector for the context of FIELD. - If FIELD is an anonymous aggregate, we will push inside it. */ - vec<constructor_elt, va_gc> **vec = vec_outer; - tree field; - while (field = fields.pop(), - ANON_AGGR_TYPE_P (TREE_TYPE (field))) - { - tree ctor; - /* If there is already an outer constructor entry for the anonymous - aggregate FIELD, use it; otherwise, insert one. */ - if (vec_safe_is_empty (*vec) - || (*vec)->last().index != field) - { - ctor = build_constructor (TREE_TYPE (field), NULL); - CONSTRUCTOR_APPEND_ELT (*vec, field, ctor); - } - else - ctor = (*vec)->last().value; - vec = &CONSTRUCTOR_ELTS (ctor); - } - - /* Now we're at the innermost field, the one that isn't an anonymous - aggregate. Add its initializer to the CONSTRUCTOR and we're done. */ - gcc_assert (fields.is_empty()); - fields.release (); - CONSTRUCTOR_APPEND_ELT (*vec, field, init); - - return true; -} - -/* Subroutine of build_constexpr_constructor_member_initializers. - The expression tree T represents a data member initialization - in a (constexpr) constructor definition. Build a pairing of - the data member with its initializer, and prepend that pair - to the existing initialization pair INITS. */ - -static bool -build_data_member_initialization (tree t, vec<constructor_elt, va_gc> **vec) -{ - tree member, init; - if (TREE_CODE (t) == CLEANUP_POINT_EXPR) - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == EXPR_STMT) - t = TREE_OPERAND (t, 0); - if (t == error_mark_node) - return false; - if (TREE_CODE (t) == STATEMENT_LIST) - { - tree_stmt_iterator i; - for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i)) - { - if (! build_data_member_initialization (tsi_stmt (i), vec)) - return false; - } - return true; - } - if (TREE_CODE (t) == CLEANUP_STMT) - { - /* We can't see a CLEANUP_STMT in a constructor for a literal class, - but we can in a constexpr constructor for a non-literal class. Just - ignore it; either all the initialization will be constant, in which - case the cleanup can't run, or it can't be constexpr. - Still recurse into CLEANUP_BODY. */ - return build_data_member_initialization (CLEANUP_BODY (t), vec); - } - if (TREE_CODE (t) == CONVERT_EXPR) - t = TREE_OPERAND (t, 0); - if (TREE_CODE (t) == INIT_EXPR - || TREE_CODE (t) == MODIFY_EXPR) - { - member = TREE_OPERAND (t, 0); - init = unshare_expr (TREE_OPERAND (t, 1)); - } - else if (TREE_CODE (t) == CALL_EXPR) - { - member = CALL_EXPR_ARG (t, 0); - /* We don't use build_cplus_new here because it complains about - abstract bases. Leaving the call unwrapped means that it has the - wrong type, but cxx_eval_constant_expression doesn't care. */ - init = unshare_expr (t); - } - else if (TREE_CODE (t) == DECL_EXPR) - /* Declaring a temporary, don't add it to the CONSTRUCTOR. */ - return true; - else - gcc_unreachable (); - if (TREE_CODE (member) == INDIRECT_REF) - member = TREE_OPERAND (member, 0); - if (TREE_CODE (member) == NOP_EXPR) - { - tree op = member; - STRIP_NOPS (op); - if (TREE_CODE (op) == ADDR_EXPR) - { - gcc_assert (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (TREE_TYPE (op)), - TREE_TYPE (TREE_TYPE (member)))); - /* Initializing a cv-qualified member; we need to look through - the const_cast. */ - member = op; - } - else if (op == current_class_ptr - && (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (TREE_TYPE (member)), - current_class_type))) - /* Delegating constructor. */ - member = op; - else - { - /* This is an initializer for an empty base; keep it for now so - we can check it in cxx_eval_bare_aggregate. */ - gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (member)))); - } - } - if (TREE_CODE (member) == ADDR_EXPR) - member = TREE_OPERAND (member, 0); - if (TREE_CODE (member) == COMPONENT_REF) - { - tree aggr = TREE_OPERAND (member, 0); - if (TREE_CODE (aggr) != COMPONENT_REF) - /* Normal member initialization. */ - member = TREE_OPERAND (member, 1); - else if (ANON_AGGR_TYPE_P (TREE_TYPE (aggr))) - /* Initializing a member of an anonymous union. */ - return build_anon_member_initialization (member, init, vec); - else - /* We're initializing a vtable pointer in a base. Leave it as - COMPONENT_REF so we remember the path to get to the vfield. */ - gcc_assert (TREE_TYPE (member) == vtbl_ptr_type_node); - } - - CONSTRUCTOR_APPEND_ELT (*vec, member, init); - return true; -} - -/* Make sure that there are no statements after LAST in the constructor - body represented by LIST. */ - -bool -check_constexpr_ctor_body (tree last, tree list) -{ - bool ok = true; - if (TREE_CODE (list) == STATEMENT_LIST) - { - tree_stmt_iterator i = tsi_last (list); - for (; !tsi_end_p (i); tsi_prev (&i)) - { - tree t = tsi_stmt (i); - if (t == last) - break; - if (TREE_CODE (t) == BIND_EXPR) - { - if (!check_constexpr_ctor_body (last, BIND_EXPR_BODY (t))) - return false; - else - continue; - } - /* We currently allow typedefs and static_assert. - FIXME allow them in the standard, too. */ - if (TREE_CODE (t) != STATIC_ASSERT) - { - ok = false; - break; - } - } - } - else if (list != last - && TREE_CODE (list) != STATIC_ASSERT) - ok = false; - if (!ok) - { - error ("constexpr constructor does not have empty body"); - DECL_DECLARED_CONSTEXPR_P (current_function_decl) = false; - } - return ok; -} - -/* V is a vector of constructor elements built up for the base and member - initializers of a constructor for TYPE. They need to be in increasing - offset order, which they might not be yet if TYPE has a primary base - which is not first in the base-clause or a vptr and at least one base - all of which are non-primary. */ - -static vec<constructor_elt, va_gc> * -sort_constexpr_mem_initializers (tree type, vec<constructor_elt, va_gc> *v) -{ - tree pri = CLASSTYPE_PRIMARY_BINFO (type); - tree field_type; - constructor_elt elt; - int i; - - if (pri) - field_type = BINFO_TYPE (pri); - else if (TYPE_CONTAINS_VPTR_P (type)) - field_type = vtbl_ptr_type_node; - else - return v; - - /* Find the element for the primary base or vptr and move it to the - beginning of the vec. */ - vec<constructor_elt, va_gc> &vref = *v; - for (i = 0; ; ++i) - if (TREE_TYPE (vref[i].index) == field_type) - break; - - if (i > 0) - { - elt = vref[i]; - for (; i > 0; --i) - vref[i] = vref[i-1]; - vref[0] = elt; - } - - return v; -} - -/* Build compile-time evalable representations of member-initializer list - for a constexpr constructor. */ - -static tree -build_constexpr_constructor_member_initializers (tree type, tree body) -{ - vec<constructor_elt, va_gc> *vec = NULL; - bool ok = true; - if (TREE_CODE (body) == MUST_NOT_THROW_EXPR - || TREE_CODE (body) == EH_SPEC_BLOCK) - body = TREE_OPERAND (body, 0); - if (TREE_CODE (body) == STATEMENT_LIST) - body = STATEMENT_LIST_HEAD (body)->stmt; - body = BIND_EXPR_BODY (body); - if (TREE_CODE (body) == CLEANUP_POINT_EXPR) - { - body = TREE_OPERAND (body, 0); - if (TREE_CODE (body) == EXPR_STMT) - body = TREE_OPERAND (body, 0); - if (TREE_CODE (body) == INIT_EXPR - && (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (TREE_OPERAND (body, 0)), - current_class_type))) - { - /* Trivial copy. */ - return TREE_OPERAND (body, 1); - } - ok = build_data_member_initialization (body, &vec); - } - else if (TREE_CODE (body) == STATEMENT_LIST) - { - tree_stmt_iterator i; - for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i)) - { - ok = build_data_member_initialization (tsi_stmt (i), &vec); - if (!ok) - break; - } - } - else if (TREE_CODE (body) == TRY_BLOCK) - { - error ("body of %<constexpr%> constructor cannot be " - "a function-try-block"); - return error_mark_node; - } - else if (EXPR_P (body)) - ok = build_data_member_initialization (body, &vec); - else - gcc_assert (errorcount > 0); - if (ok) - { - if (vec_safe_length (vec) > 0) - { - /* In a delegating constructor, return the target. */ - constructor_elt *ce = &(*vec)[0]; - if (ce->index == current_class_ptr) - { - body = ce->value; - vec_free (vec); - return body; - } - } - vec = sort_constexpr_mem_initializers (type, vec); - return build_constructor (type, vec); - } - else - return error_mark_node; -} - -/* Subroutine of register_constexpr_fundef. BODY is the body of a function - declared to be constexpr, or a sub-statement thereof. Returns the - return value if suitable, error_mark_node for a statement not allowed in - a constexpr function, or NULL_TREE if no return value was found. */ - -static tree -constexpr_fn_retval (tree body) -{ - switch (TREE_CODE (body)) - { - case STATEMENT_LIST: - { - tree_stmt_iterator i; - tree expr = NULL_TREE; - for (i = tsi_start (body); !tsi_end_p (i); tsi_next (&i)) - { - tree s = constexpr_fn_retval (tsi_stmt (i)); - if (s == error_mark_node) - return error_mark_node; - else if (s == NULL_TREE) - /* Keep iterating. */; - else if (expr) - /* Multiple return statements. */ - return error_mark_node; - else - expr = s; - } - return expr; - } - - case RETURN_EXPR: - return unshare_expr (TREE_OPERAND (body, 0)); - - case DECL_EXPR: - if (TREE_CODE (DECL_EXPR_DECL (body)) == USING_DECL) - return NULL_TREE; - return error_mark_node; - - case CLEANUP_POINT_EXPR: - return constexpr_fn_retval (TREE_OPERAND (body, 0)); - - case USING_STMT: - return NULL_TREE; - - default: - return error_mark_node; - } -} - -/* Subroutine of register_constexpr_fundef. BODY is the DECL_SAVED_TREE of - FUN; do the necessary transformations to turn it into a single expression - that we can store in the hash table. */ - -static tree -massage_constexpr_body (tree fun, tree body) -{ - if (DECL_CONSTRUCTOR_P (fun)) - body = build_constexpr_constructor_member_initializers - (DECL_CONTEXT (fun), body); - else - { - if (TREE_CODE (body) == EH_SPEC_BLOCK) - body = EH_SPEC_STMTS (body); - if (TREE_CODE (body) == MUST_NOT_THROW_EXPR) - body = TREE_OPERAND (body, 0); - if (TREE_CODE (body) == BIND_EXPR) - body = BIND_EXPR_BODY (body); - body = constexpr_fn_retval (body); - } - return body; -} - -/* FUN is a constexpr constructor with massaged body BODY. Return true - if some bases/fields are uninitialized, and complain if COMPLAIN. */ - -static bool -cx_check_missing_mem_inits (tree fun, tree body, bool complain) -{ - bool bad; - tree field; - unsigned i, nelts; - tree ctype; - - if (TREE_CODE (body) != CONSTRUCTOR) - return false; - - nelts = CONSTRUCTOR_NELTS (body); - ctype = DECL_CONTEXT (fun); - field = TYPE_FIELDS (ctype); - - if (TREE_CODE (ctype) == UNION_TYPE) - { - if (nelts == 0 && next_initializable_field (field)) - { - if (complain) - error ("%<constexpr%> constructor for union %qT must " - "initialize exactly one non-static data member", ctype); - return true; - } - return false; - } - - bad = false; - for (i = 0; i <= nelts; ++i) - { - tree index; - if (i == nelts) - index = NULL_TREE; - else - { - index = CONSTRUCTOR_ELT (body, i)->index; - /* Skip base and vtable inits. */ - if (TREE_CODE (index) != FIELD_DECL - || DECL_ARTIFICIAL (index)) - continue; - } - for (; field != index; field = DECL_CHAIN (field)) - { - tree ftype; - if (TREE_CODE (field) != FIELD_DECL - || (DECL_C_BIT_FIELD (field) && !DECL_NAME (field)) - || DECL_ARTIFICIAL (field)) - continue; - ftype = strip_array_types (TREE_TYPE (field)); - if (type_has_constexpr_default_constructor (ftype)) - { - /* It's OK to skip a member with a trivial constexpr ctor. - A constexpr ctor that isn't trivial should have been - added in by now. */ - gcc_checking_assert (!TYPE_HAS_COMPLEX_DFLT (ftype) - || errorcount != 0); - continue; - } - if (!complain) - return true; - error ("uninitialized member %qD in %<constexpr%> constructor", - field); - bad = true; - } - if (field == NULL_TREE) - break; - field = DECL_CHAIN (field); - } - - return bad; -} - -/* We are processing the definition of the constexpr function FUN. - Check that its BODY fulfills the propriate requirements and - enter it in the constexpr function definition table. - For constructor BODY is actually the TREE_LIST of the - member-initializer list. */ - -tree -register_constexpr_fundef (tree fun, tree body) -{ - constexpr_fundef entry; - constexpr_fundef **slot; - - if (!is_valid_constexpr_fn (fun, !DECL_GENERATED_P (fun))) - return NULL; - - body = massage_constexpr_body (fun, body); - if (body == NULL_TREE || body == error_mark_node) - { - if (!DECL_CONSTRUCTOR_P (fun)) - error ("body of constexpr function %qD not a return-statement", fun); - return NULL; - } - - if (!potential_rvalue_constant_expression (body)) - { - if (!DECL_GENERATED_P (fun)) - require_potential_rvalue_constant_expression (body); - return NULL; - } - - if (DECL_CONSTRUCTOR_P (fun) - && cx_check_missing_mem_inits (fun, body, !DECL_GENERATED_P (fun))) - return NULL; - - /* Create the constexpr function table if necessary. */ - if (constexpr_fundef_table == NULL) - constexpr_fundef_table = htab_create_ggc (101, - constexpr_fundef_hash, - constexpr_fundef_equal, - ggc_free); - entry.decl = fun; - entry.body = body; - slot = (constexpr_fundef **) - htab_find_slot (constexpr_fundef_table, &entry, INSERT); - - gcc_assert (*slot == NULL); - *slot = ggc_alloc_constexpr_fundef (); - **slot = entry; - - return fun; -} - -/* FUN is a non-constexpr function called in a context that requires a - constant expression. If it comes from a constexpr template, explain why - the instantiation isn't constexpr. */ - -void -explain_invalid_constexpr_fn (tree fun) -{ - static struct pointer_set_t *diagnosed; - tree body; - location_t save_loc; - /* Only diagnose defaulted functions or instantiations. */ - if (!DECL_DEFAULTED_FN (fun) - && !is_instantiation_of_constexpr (fun)) - return; - if (diagnosed == NULL) - diagnosed = pointer_set_create (); - if (pointer_set_insert (diagnosed, fun) != 0) - /* Already explained. */ - return; - - save_loc = input_location; - input_location = DECL_SOURCE_LOCATION (fun); - inform (0, "%q+D is not usable as a constexpr function because:", fun); - /* First check the declaration. */ - if (is_valid_constexpr_fn (fun, true)) - { - /* Then if it's OK, the body. */ - if (DECL_DEFAULTED_FN (fun)) - explain_implicit_non_constexpr (fun); - else - { - body = massage_constexpr_body (fun, DECL_SAVED_TREE (fun)); - require_potential_rvalue_constant_expression (body); - if (DECL_CONSTRUCTOR_P (fun)) - cx_check_missing_mem_inits (fun, body, true); - } - } - input_location = save_loc; -} - -/* Objects of this type represent calls to constexpr functions - along with the bindings of parameters to their arguments, for - the purpose of compile time evaluation. */ - -typedef struct GTY(()) constexpr_call { - /* Description of the constexpr function definition. */ - constexpr_fundef *fundef; - /* Parameter bindings environment. A TREE_LIST where each TREE_PURPOSE - is a parameter _DECL and the TREE_VALUE is the value of the parameter. - Note: This arrangement is made to accomodate the use of - iterative_hash_template_arg (see pt.c). If you change this - representation, also change the hash calculation in - cxx_eval_call_expression. */ - tree bindings; - /* Result of the call. - NULL means the call is being evaluated. - error_mark_node means that the evaluation was erroneous; - otherwise, the actuall value of the call. */ - tree result; - /* The hash of this call; we remember it here to avoid having to - recalculate it when expanding the hash table. */ - hashval_t hash; -} constexpr_call; - -/* A table of all constexpr calls that have been evaluated by the - compiler in this translation unit. */ - -static GTY ((param_is (constexpr_call))) htab_t constexpr_call_table; - -static tree cxx_eval_constant_expression (const constexpr_call *, tree, - bool, bool, bool *, bool *); - -/* Compute a hash value for a constexpr call representation. */ - -static hashval_t -constexpr_call_hash (const void *p) -{ - const constexpr_call *info = (const constexpr_call *) p; - return info->hash; -} - -/* Return 1 if the objects pointed to by P and Q represent calls - to the same constexpr function with the same arguments. - Otherwise, return 0. */ - -static int -constexpr_call_equal (const void *p, const void *q) -{ - const constexpr_call *lhs = (const constexpr_call *) p; - const constexpr_call *rhs = (const constexpr_call *) q; - tree lhs_bindings; - tree rhs_bindings; - if (lhs == rhs) - return 1; - if (!constexpr_fundef_equal (lhs->fundef, rhs->fundef)) - return 0; - lhs_bindings = lhs->bindings; - rhs_bindings = rhs->bindings; - while (lhs_bindings != NULL && rhs_bindings != NULL) - { - tree lhs_arg = TREE_VALUE (lhs_bindings); - tree rhs_arg = TREE_VALUE (rhs_bindings); - gcc_assert (TREE_TYPE (lhs_arg) == TREE_TYPE (rhs_arg)); - if (!cp_tree_equal (lhs_arg, rhs_arg)) - return 0; - lhs_bindings = TREE_CHAIN (lhs_bindings); - rhs_bindings = TREE_CHAIN (rhs_bindings); - } - return lhs_bindings == rhs_bindings; -} - -/* Initialize the constexpr call table, if needed. */ - -static void -maybe_initialize_constexpr_call_table (void) -{ - if (constexpr_call_table == NULL) - constexpr_call_table = htab_create_ggc (101, - constexpr_call_hash, - constexpr_call_equal, - ggc_free); -} - -/* Return true if T designates the implied `this' parameter. */ - -static inline bool -is_this_parameter (tree t) -{ - return t == current_class_ptr; -} - -/* We have an expression tree T that represents a call, either CALL_EXPR - or AGGR_INIT_EXPR. If the call is lexically to a named function, - retrun the _DECL for that function. */ - -static tree -get_function_named_in_call (tree t) -{ - tree fun = NULL; - switch (TREE_CODE (t)) - { - case CALL_EXPR: - fun = CALL_EXPR_FN (t); - break; - - case AGGR_INIT_EXPR: - fun = AGGR_INIT_EXPR_FN (t); - break; - - default: - gcc_unreachable(); - break; - } - if (TREE_CODE (fun) == ADDR_EXPR - && TREE_CODE (TREE_OPERAND (fun, 0)) == FUNCTION_DECL) - fun = TREE_OPERAND (fun, 0); - return fun; -} - -/* We have an expression tree T that represents a call, either CALL_EXPR - or AGGR_INIT_EXPR. Return the Nth argument. */ - -static inline tree -get_nth_callarg (tree t, int n) -{ - switch (TREE_CODE (t)) - { - case CALL_EXPR: - return CALL_EXPR_ARG (t, n); - - case AGGR_INIT_EXPR: - return AGGR_INIT_EXPR_ARG (t, n); - - default: - gcc_unreachable (); - return NULL; - } -} - -/* Look up the binding of the function parameter T in a constexpr - function call context CALL. */ - -static tree -lookup_parameter_binding (const constexpr_call *call, tree t) -{ - tree b = purpose_member (t, call->bindings); - return TREE_VALUE (b); -} - -/* Attempt to evaluate T which represents a call to a builtin function. - We assume here that all builtin functions evaluate to scalar types - represented by _CST nodes. */ - -static tree -cxx_eval_builtin_function_call (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - const int nargs = call_expr_nargs (t); - tree *args = (tree *) alloca (nargs * sizeof (tree)); - tree new_call; - int i; - for (i = 0; i < nargs; ++i) - { - args[i] = cxx_eval_constant_expression (call, CALL_EXPR_ARG (t, i), - allow_non_constant, addr, - non_constant_p, overflow_p); - if (allow_non_constant && *non_constant_p) - return t; - } - if (*non_constant_p) - return t; - new_call = build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t), - CALL_EXPR_FN (t), nargs, args); - new_call = fold (new_call); - VERIFY_CONSTANT (new_call); - return new_call; -} - -/* TEMP is the constant value of a temporary object of type TYPE. Adjust - the type of the value to match. */ - -static tree -adjust_temp_type (tree type, tree temp) -{ - if (TREE_TYPE (temp) == type) - return temp; - /* Avoid wrapping an aggregate value in a NOP_EXPR. */ - if (TREE_CODE (temp) == CONSTRUCTOR) - return build_constructor (type, CONSTRUCTOR_ELTS (temp)); - gcc_assert (scalarish_type_p (type)); - return cp_fold_convert (type, temp); -} - -/* Subroutine of cxx_eval_call_expression. - We are processing a call expression (either CALL_EXPR or - AGGR_INIT_EXPR) in the call context of OLD_CALL. Evaluate - all arguments and bind their values to correspondings - parameters, making up the NEW_CALL context. */ - -static void -cxx_bind_parameters_in_call (const constexpr_call *old_call, tree t, - constexpr_call *new_call, - bool allow_non_constant, - bool *non_constant_p, bool *overflow_p) -{ - const int nargs = call_expr_nargs (t); - tree fun = new_call->fundef->decl; - tree parms = DECL_ARGUMENTS (fun); - int i; - for (i = 0; i < nargs; ++i) - { - tree x, arg; - tree type = parms ? TREE_TYPE (parms) : void_type_node; - /* For member function, the first argument is a pointer to the implied - object. And for an object contruction, don't bind `this' before - it is fully constructed. */ - if (i == 0 && DECL_CONSTRUCTOR_P (fun)) - goto next; - x = get_nth_callarg (t, i); - if (parms && DECL_BY_REFERENCE (parms)) - { - /* cp_genericize made this a reference for argument passing, but - we don't want to treat it like one for constexpr evaluation. */ - gcc_assert (TREE_CODE (type) == REFERENCE_TYPE); - gcc_assert (TREE_CODE (TREE_TYPE (x)) == REFERENCE_TYPE); - type = TREE_TYPE (type); - x = convert_from_reference (x); - } - arg = cxx_eval_constant_expression (old_call, x, allow_non_constant, - TREE_CODE (type) == REFERENCE_TYPE, - non_constant_p, overflow_p); - /* Don't VERIFY_CONSTANT here. */ - if (*non_constant_p && allow_non_constant) - return; - /* Just discard ellipsis args after checking their constantitude. */ - if (!parms) - continue; - if (*non_constant_p) - /* Don't try to adjust the type of non-constant args. */ - goto next; - - /* Make sure the binding has the same type as the parm. */ - if (TREE_CODE (type) != REFERENCE_TYPE) - arg = adjust_temp_type (type, arg); - new_call->bindings = tree_cons (parms, arg, new_call->bindings); - next: - parms = TREE_CHAIN (parms); - } -} - -/* Variables and functions to manage constexpr call expansion context. - These do not need to be marked for PCH or GC. */ - -/* FIXME remember and print actual constant arguments. */ -static vec<tree> call_stack = vNULL; -static int call_stack_tick; -static int last_cx_error_tick; - -static bool -push_cx_call_context (tree call) -{ - ++call_stack_tick; - if (!EXPR_HAS_LOCATION (call)) - SET_EXPR_LOCATION (call, input_location); - call_stack.safe_push (call); - if (call_stack.length () > (unsigned) max_constexpr_depth) - return false; - return true; -} - -static void -pop_cx_call_context (void) -{ - ++call_stack_tick; - call_stack.pop (); -} - -vec<tree> -cx_error_context (void) -{ - vec<tree> r = vNULL; - if (call_stack_tick != last_cx_error_tick - && !call_stack.is_empty ()) - r = call_stack; - last_cx_error_tick = call_stack_tick; - return r; -} - -/* Subroutine of cxx_eval_constant_expression. - Evaluate the call expression tree T in the context of OLD_CALL expression - evaluation. */ - -static tree -cxx_eval_call_expression (const constexpr_call *old_call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - location_t loc = EXPR_LOC_OR_HERE (t); - tree fun = get_function_named_in_call (t); - tree result; - constexpr_call new_call = { NULL, NULL, NULL, 0 }; - constexpr_call **slot; - constexpr_call *entry; - bool depth_ok; - - if (TREE_CODE (fun) != FUNCTION_DECL) - { - /* Might be a constexpr function pointer. */ - fun = cxx_eval_constant_expression (old_call, fun, allow_non_constant, - /*addr*/false, non_constant_p, overflow_p); - if (TREE_CODE (fun) == ADDR_EXPR) - fun = TREE_OPERAND (fun, 0); - } - if (TREE_CODE (fun) != FUNCTION_DECL) - { - if (!allow_non_constant && !*non_constant_p) - error_at (loc, "expression %qE does not designate a constexpr " - "function", fun); - *non_constant_p = true; - return t; - } - if (DECL_CLONED_FUNCTION_P (fun)) - fun = DECL_CLONED_FUNCTION (fun); - if (is_builtin_fn (fun)) - return cxx_eval_builtin_function_call (old_call, t, allow_non_constant, - addr, non_constant_p, overflow_p); - if (!DECL_DECLARED_CONSTEXPR_P (fun)) - { - if (!allow_non_constant) - { - error_at (loc, "call to non-constexpr function %qD", fun); - explain_invalid_constexpr_fn (fun); - } - *non_constant_p = true; - return t; - } - - /* Shortcut trivial copy constructor/op=. */ - if (call_expr_nargs (t) == 2 && trivial_fn_p (fun)) - { - tree arg = convert_from_reference (get_nth_callarg (t, 1)); - return cxx_eval_constant_expression (old_call, arg, allow_non_constant, - addr, non_constant_p, overflow_p); - } - - /* If in direct recursive call, optimize definition search. */ - if (old_call != NULL && old_call->fundef->decl == fun) - new_call.fundef = old_call->fundef; - else - { - new_call.fundef = retrieve_constexpr_fundef (fun); - if (new_call.fundef == NULL || new_call.fundef->body == NULL) - { - if (!allow_non_constant) - { - if (DECL_INITIAL (fun)) - { - /* The definition of fun was somehow unsuitable. */ - error_at (loc, "%qD called in a constant expression", fun); - explain_invalid_constexpr_fn (fun); - } - else - error_at (loc, "%qD used before its definition", fun); - } - *non_constant_p = true; - return t; - } - } - cxx_bind_parameters_in_call (old_call, t, &new_call, - allow_non_constant, non_constant_p, overflow_p); - if (*non_constant_p) - return t; - - depth_ok = push_cx_call_context (t); - - new_call.hash - = iterative_hash_template_arg (new_call.bindings, - constexpr_fundef_hash (new_call.fundef)); - - /* If we have seen this call before, we are done. */ - maybe_initialize_constexpr_call_table (); - slot = (constexpr_call **) - htab_find_slot (constexpr_call_table, &new_call, INSERT); - entry = *slot; - if (entry == NULL) - { - /* We need to keep a pointer to the entry, not just the slot, as the - slot can move in the call to cxx_eval_builtin_function_call. */ - *slot = entry = ggc_alloc_constexpr_call (); - *entry = new_call; - } - /* Calls which are in progress have their result set to NULL - so that we can detect circular dependencies. */ - else if (entry->result == NULL) - { - if (!allow_non_constant) - error ("call has circular dependency"); - *non_constant_p = true; - entry->result = result = error_mark_node; - } - - if (!depth_ok) - { - if (!allow_non_constant) - error ("constexpr evaluation depth exceeds maximum of %d (use " - "-fconstexpr-depth= to increase the maximum)", - max_constexpr_depth); - *non_constant_p = true; - entry->result = result = error_mark_node; - } - else - { - result = entry->result; - if (!result || result == error_mark_node) - result = (cxx_eval_constant_expression - (&new_call, new_call.fundef->body, - allow_non_constant, addr, - non_constant_p, overflow_p)); - if (result == error_mark_node) - *non_constant_p = true; - if (*non_constant_p) - entry->result = result = error_mark_node; - else - { - /* If this was a call to initialize an object, set the type of - the CONSTRUCTOR to the type of that object. */ - if (DECL_CONSTRUCTOR_P (fun)) - { - tree ob_arg = get_nth_callarg (t, 0); - STRIP_NOPS (ob_arg); - gcc_assert (TREE_CODE (TREE_TYPE (ob_arg)) == POINTER_TYPE - && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (ob_arg)))); - result = adjust_temp_type (TREE_TYPE (TREE_TYPE (ob_arg)), - result); - } - entry->result = result; - } - } - - pop_cx_call_context (); - return unshare_expr (result); -} - -/* FIXME speed this up, it's taking 16% of compile time on sieve testcase. */ - -bool -reduced_constant_expression_p (tree t) -{ - /* FIXME are we calling this too much? */ - return initializer_constant_valid_p (t, TREE_TYPE (t)) != NULL_TREE; -} - -/* Some expressions may have constant operands but are not constant - themselves, such as 1/0. Call this function (or rather, the macro - following it) to check for that condition. - - We only call this in places that require an arithmetic constant, not in - places where we might have a non-constant expression that can be a - component of a constant expression, such as the address of a constexpr - variable that might be dereferenced later. */ - -static bool -verify_constant (tree t, bool allow_non_constant, bool *non_constant_p, - bool *overflow_p) -{ - if (!*non_constant_p && !reduced_constant_expression_p (t)) - { - if (!allow_non_constant) - error ("%q+E is not a constant expression", t); - *non_constant_p = true; - } - if (TREE_OVERFLOW_P (t)) - { - if (!allow_non_constant) - { - permerror (input_location, "overflow in constant expression"); - /* If we're being permissive (and are in an enforcing - context), ignore the overflow. */ - if (flag_permissive) - return *non_constant_p; - } - *overflow_p = true; - } - return *non_constant_p; -} - -/* Subroutine of cxx_eval_constant_expression. - Attempt to reduce the unary expression tree T to a compile time value. - If successful, return the value. Otherwise issue a diagnostic - and return error_mark_node. */ - -static tree -cxx_eval_unary_expression (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - tree r; - tree orig_arg = TREE_OPERAND (t, 0); - tree arg = cxx_eval_constant_expression (call, orig_arg, allow_non_constant, - addr, non_constant_p, overflow_p); - VERIFY_CONSTANT (arg); - if (arg == orig_arg) - return t; - r = fold_build1 (TREE_CODE (t), TREE_TYPE (t), arg); - VERIFY_CONSTANT (r); - return r; -} - -/* Subroutine of cxx_eval_constant_expression. - Like cxx_eval_unary_expression, except for binary expressions. */ - -static tree -cxx_eval_binary_expression (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - tree r; - tree orig_lhs = TREE_OPERAND (t, 0); - tree orig_rhs = TREE_OPERAND (t, 1); - tree lhs, rhs; - lhs = cxx_eval_constant_expression (call, orig_lhs, - allow_non_constant, addr, - non_constant_p, overflow_p); - VERIFY_CONSTANT (lhs); - rhs = cxx_eval_constant_expression (call, orig_rhs, - allow_non_constant, addr, - non_constant_p, overflow_p); - VERIFY_CONSTANT (rhs); - if (lhs == orig_lhs && rhs == orig_rhs) - return t; - r = fold_build2 (TREE_CODE (t), TREE_TYPE (t), lhs, rhs); - VERIFY_CONSTANT (r); - return r; -} - -/* Subroutine of cxx_eval_constant_expression. - Attempt to evaluate condition expressions. Dead branches are not - looked into. */ - -static tree -cxx_eval_conditional_expression (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - tree val = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0), - allow_non_constant, addr, - non_constant_p, overflow_p); - VERIFY_CONSTANT (val); - /* Don't VERIFY_CONSTANT the other operands. */ - if (integer_zerop (val)) - return cxx_eval_constant_expression (call, TREE_OPERAND (t, 2), - allow_non_constant, addr, - non_constant_p, overflow_p); - return cxx_eval_constant_expression (call, TREE_OPERAND (t, 1), - allow_non_constant, addr, - non_constant_p, overflow_p); -} - -/* Subroutine of cxx_eval_constant_expression. - Attempt to reduce a reference to an array slot. */ - -static tree -cxx_eval_array_reference (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - tree oldary = TREE_OPERAND (t, 0); - tree ary = cxx_eval_constant_expression (call, oldary, - allow_non_constant, addr, - non_constant_p, overflow_p); - tree index, oldidx; - HOST_WIDE_INT i; - tree elem_type; - unsigned len, elem_nchars = 1; - if (*non_constant_p) - return t; - oldidx = TREE_OPERAND (t, 1); - index = cxx_eval_constant_expression (call, oldidx, - allow_non_constant, false, - non_constant_p, overflow_p); - VERIFY_CONSTANT (index); - if (addr && ary == oldary && index == oldidx) - return t; - else if (addr) - return build4 (ARRAY_REF, TREE_TYPE (t), ary, index, NULL, NULL); - elem_type = TREE_TYPE (TREE_TYPE (ary)); - if (TREE_CODE (ary) == CONSTRUCTOR) - len = CONSTRUCTOR_NELTS (ary); - else if (TREE_CODE (ary) == STRING_CST) - { - elem_nchars = (TYPE_PRECISION (elem_type) - / TYPE_PRECISION (char_type_node)); - len = (unsigned) TREE_STRING_LENGTH (ary) / elem_nchars; - } - else - { - /* We can't do anything with other tree codes, so use - VERIFY_CONSTANT to complain and fail. */ - VERIFY_CONSTANT (ary); - gcc_unreachable (); - } - if (compare_tree_int (index, len) >= 0) - { - if (tree_int_cst_lt (index, array_type_nelts_top (TREE_TYPE (ary)))) - { - /* If it's within the array bounds but doesn't have an explicit - initializer, it's value-initialized. */ - tree val = build_value_init (elem_type, tf_warning_or_error); - return cxx_eval_constant_expression (call, val, - allow_non_constant, addr, - non_constant_p, overflow_p); - } - - if (!allow_non_constant) - error ("array subscript out of bound"); - *non_constant_p = true; - return t; - } - else if (tree_int_cst_lt (index, integer_zero_node)) - { - if (!allow_non_constant) - error ("negative array subscript"); - *non_constant_p = true; - return t; - } - i = tree_low_cst (index, 0); - if (TREE_CODE (ary) == CONSTRUCTOR) - return (*CONSTRUCTOR_ELTS (ary))[i].value; - else if (elem_nchars == 1) - return build_int_cst (cv_unqualified (TREE_TYPE (TREE_TYPE (ary))), - TREE_STRING_POINTER (ary)[i]); - else - { - tree type = cv_unqualified (TREE_TYPE (TREE_TYPE (ary))); - return native_interpret_expr (type, (const unsigned char *) - TREE_STRING_POINTER (ary) - + i * elem_nchars, elem_nchars); - } - /* Don't VERIFY_CONSTANT here. */ -} - -/* Subroutine of cxx_eval_constant_expression. - Attempt to reduce a field access of a value of class type. */ - -static tree -cxx_eval_component_reference (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - unsigned HOST_WIDE_INT i; - tree field; - tree value; - tree part = TREE_OPERAND (t, 1); - tree orig_whole = TREE_OPERAND (t, 0); - tree whole = cxx_eval_constant_expression (call, orig_whole, - allow_non_constant, addr, - non_constant_p, overflow_p); - if (whole == orig_whole) - return t; - if (addr) - return fold_build3 (COMPONENT_REF, TREE_TYPE (t), - whole, part, NULL_TREE); - /* Don't VERIFY_CONSTANT here; we only want to check that we got a - CONSTRUCTOR. */ - if (!*non_constant_p && TREE_CODE (whole) != CONSTRUCTOR) - { - if (!allow_non_constant) - error ("%qE is not a constant expression", orig_whole); - *non_constant_p = true; - } - if (DECL_MUTABLE_P (part)) - { - if (!allow_non_constant) - error ("mutable %qD is not usable in a constant expression", part); - *non_constant_p = true; - } - if (*non_constant_p) - return t; - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value) - { - if (field == part) - return value; - } - if (TREE_CODE (TREE_TYPE (whole)) == UNION_TYPE - && CONSTRUCTOR_NELTS (whole) > 0) - { - /* DR 1188 says we don't have to deal with this. */ - if (!allow_non_constant) - error ("accessing %qD member instead of initialized %qD member in " - "constant expression", part, CONSTRUCTOR_ELT (whole, 0)->index); - *non_constant_p = true; - return t; - } - - /* If there's no explicit init for this field, it's value-initialized. */ - value = build_value_init (TREE_TYPE (t), tf_warning_or_error); - return cxx_eval_constant_expression (call, value, - allow_non_constant, addr, - non_constant_p, overflow_p); -} - -/* Subroutine of cxx_eval_constant_expression. - Attempt to reduce a field access of a value of class type that is - expressed as a BIT_FIELD_REF. */ - -static tree -cxx_eval_bit_field_ref (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - tree orig_whole = TREE_OPERAND (t, 0); - tree retval, fldval, utype, mask; - bool fld_seen = false; - HOST_WIDE_INT istart, isize; - tree whole = cxx_eval_constant_expression (call, orig_whole, - allow_non_constant, addr, - non_constant_p, overflow_p); - tree start, field, value; - unsigned HOST_WIDE_INT i; - - if (whole == orig_whole) - return t; - /* Don't VERIFY_CONSTANT here; we only want to check that we got a - CONSTRUCTOR. */ - if (!*non_constant_p && TREE_CODE (whole) != CONSTRUCTOR) - { - if (!allow_non_constant) - error ("%qE is not a constant expression", orig_whole); - *non_constant_p = true; - } - if (*non_constant_p) - return t; - - start = TREE_OPERAND (t, 2); - istart = tree_low_cst (start, 0); - isize = tree_low_cst (TREE_OPERAND (t, 1), 0); - utype = TREE_TYPE (t); - if (!TYPE_UNSIGNED (utype)) - utype = build_nonstandard_integer_type (TYPE_PRECISION (utype), 1); - retval = build_int_cst (utype, 0); - FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (whole), i, field, value) - { - tree bitpos = bit_position (field); - if (bitpos == start && DECL_SIZE (field) == TREE_OPERAND (t, 1)) - return value; - if (TREE_CODE (TREE_TYPE (field)) == INTEGER_TYPE - && TREE_CODE (value) == INTEGER_CST - && host_integerp (bitpos, 0) - && host_integerp (DECL_SIZE (field), 0)) - { - HOST_WIDE_INT bit = tree_low_cst (bitpos, 0); - HOST_WIDE_INT sz = tree_low_cst (DECL_SIZE (field), 0); - HOST_WIDE_INT shift; - if (bit >= istart && bit + sz <= istart + isize) - { - fldval = fold_convert (utype, value); - mask = build_int_cst_type (utype, -1); - mask = fold_build2 (LSHIFT_EXPR, utype, mask, - size_int (TYPE_PRECISION (utype) - sz)); - mask = fold_build2 (RSHIFT_EXPR, utype, mask, - size_int (TYPE_PRECISION (utype) - sz)); - fldval = fold_build2 (BIT_AND_EXPR, utype, fldval, mask); - shift = bit - istart; - if (BYTES_BIG_ENDIAN) - shift = TYPE_PRECISION (utype) - shift - sz; - fldval = fold_build2 (LSHIFT_EXPR, utype, fldval, - size_int (shift)); - retval = fold_build2 (BIT_IOR_EXPR, utype, retval, fldval); - fld_seen = true; - } - } - } - if (fld_seen) - return fold_convert (TREE_TYPE (t), retval); - gcc_unreachable (); - return error_mark_node; -} - -/* Subroutine of cxx_eval_constant_expression. - Evaluate a short-circuited logical expression T in the context - of a given constexpr CALL. BAILOUT_VALUE is the value for - early return. CONTINUE_VALUE is used here purely for - sanity check purposes. */ - -static tree -cxx_eval_logical_expression (const constexpr_call *call, tree t, - tree bailout_value, tree continue_value, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - tree r; - tree lhs = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0), - allow_non_constant, addr, - non_constant_p, overflow_p); - VERIFY_CONSTANT (lhs); - if (tree_int_cst_equal (lhs, bailout_value)) - return lhs; - gcc_assert (tree_int_cst_equal (lhs, continue_value)); - r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1), - allow_non_constant, addr, non_constant_p, overflow_p); - VERIFY_CONSTANT (r); - return r; -} - -/* REF is a COMPONENT_REF designating a particular field. V is a vector of - CONSTRUCTOR elements to initialize (part of) an object containing that - field. Return a pointer to the constructor_elt corresponding to the - initialization of the field. */ - -static constructor_elt * -base_field_constructor_elt (vec<constructor_elt, va_gc> *v, tree ref) -{ - tree aggr = TREE_OPERAND (ref, 0); - tree field = TREE_OPERAND (ref, 1); - HOST_WIDE_INT i; - constructor_elt *ce; - - gcc_assert (TREE_CODE (ref) == COMPONENT_REF); - - if (TREE_CODE (aggr) == COMPONENT_REF) - { - constructor_elt *base_ce - = base_field_constructor_elt (v, aggr); - v = CONSTRUCTOR_ELTS (base_ce->value); - } - - for (i = 0; vec_safe_iterate (v, i, &ce); ++i) - if (ce->index == field) - return ce; - - gcc_unreachable (); - return NULL; -} - -/* Subroutine of cxx_eval_constant_expression. - The expression tree T denotes a C-style array or a C-style - aggregate. Reduce it to a constant expression. */ - -static tree -cxx_eval_bare_aggregate (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t); - vec<constructor_elt, va_gc> *n; - vec_alloc (n, vec_safe_length (v)); - constructor_elt *ce; - HOST_WIDE_INT i; - bool changed = false; - gcc_assert (!BRACE_ENCLOSED_INITIALIZER_P (t)); - for (i = 0; vec_safe_iterate (v, i, &ce); ++i) - { - tree elt = cxx_eval_constant_expression (call, ce->value, - allow_non_constant, addr, - non_constant_p, overflow_p); - /* Don't VERIFY_CONSTANT here. */ - if (allow_non_constant && *non_constant_p) - goto fail; - if (elt != ce->value) - changed = true; - if (ce->index && TREE_CODE (ce->index) == COMPONENT_REF) - { - /* This is an initialization of a vfield inside a base - subaggregate that we already initialized; push this - initialization into the previous initialization. */ - constructor_elt *inner = base_field_constructor_elt (n, ce->index); - inner->value = elt; - } - else if (ce->index && TREE_CODE (ce->index) == NOP_EXPR) - { - /* This is an initializer for an empty base; now that we've - checked that it's constant, we can ignore it. */ - gcc_assert (is_empty_class (TREE_TYPE (TREE_TYPE (ce->index)))); - } - else - CONSTRUCTOR_APPEND_ELT (n, ce->index, elt); - } - if (*non_constant_p || !changed) - { - fail: - vec_free (n); - return t; - } - t = build_constructor (TREE_TYPE (t), n); - TREE_CONSTANT (t) = true; - if (TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE) - t = fold (t); - return t; -} - -/* Subroutine of cxx_eval_constant_expression. - The expression tree T is a VEC_INIT_EXPR which denotes the desired - initialization of a non-static data member of array type. Reduce it to a - CONSTRUCTOR. - - Note that apart from value-initialization (when VALUE_INIT is true), - this is only intended to support value-initialization and the - initializations done by defaulted constructors for classes with - non-static data members of array type. In this case, VEC_INIT_EXPR_INIT - will either be NULL_TREE for the default constructor, or a COMPONENT_REF - for the copy/move constructor. */ - -static tree -cxx_eval_vec_init_1 (const constexpr_call *call, tree atype, tree init, - bool value_init, bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - tree elttype = TREE_TYPE (atype); - int max = tree_low_cst (array_type_nelts (atype), 0); - vec<constructor_elt, va_gc> *n; - vec_alloc (n, max + 1); - bool pre_init = false; - int i; - - /* For the default constructor, build up a call to the default - constructor of the element type. We only need to handle class types - here, as for a constructor to be constexpr, all members must be - initialized, which for a defaulted default constructor means they must - be of a class type with a constexpr default constructor. */ - if (TREE_CODE (elttype) == ARRAY_TYPE) - /* We only do this at the lowest level. */; - else if (value_init) - { - init = build_value_init (elttype, tf_warning_or_error); - init = cxx_eval_constant_expression - (call, init, allow_non_constant, addr, non_constant_p, overflow_p); - pre_init = true; - } - else if (!init) - { - vec<tree, va_gc> *argvec = make_tree_vector (); - init = build_special_member_call (NULL_TREE, complete_ctor_identifier, - &argvec, elttype, LOOKUP_NORMAL, - tf_warning_or_error); - release_tree_vector (argvec); - init = cxx_eval_constant_expression (call, init, allow_non_constant, - addr, non_constant_p, overflow_p); - pre_init = true; - } - - if (*non_constant_p && !allow_non_constant) - goto fail; - - for (i = 0; i <= max; ++i) - { - tree idx = build_int_cst (size_type_node, i); - tree eltinit; - if (TREE_CODE (elttype) == ARRAY_TYPE) - { - /* A multidimensional array; recurse. */ - if (value_init || init == NULL_TREE) - eltinit = NULL_TREE; - else - eltinit = cp_build_array_ref (input_location, init, idx, - tf_warning_or_error); - eltinit = cxx_eval_vec_init_1 (call, elttype, eltinit, value_init, - allow_non_constant, addr, - non_constant_p, overflow_p); - } - else if (pre_init) - { - /* Initializing an element using value or default initialization - we just pre-built above. */ - if (i == 0) - eltinit = init; - else - eltinit = unshare_expr (init); - } - else - { - /* Copying an element. */ - vec<tree, va_gc> *argvec; - gcc_assert (same_type_ignoring_top_level_qualifiers_p - (atype, TREE_TYPE (init))); - eltinit = cp_build_array_ref (input_location, init, idx, - tf_warning_or_error); - if (!real_lvalue_p (init)) - eltinit = move (eltinit); - argvec = make_tree_vector (); - argvec->quick_push (eltinit); - eltinit = (build_special_member_call - (NULL_TREE, complete_ctor_identifier, &argvec, - elttype, LOOKUP_NORMAL, tf_warning_or_error)); - release_tree_vector (argvec); - eltinit = cxx_eval_constant_expression - (call, eltinit, allow_non_constant, addr, non_constant_p, overflow_p); - } - if (*non_constant_p && !allow_non_constant) - goto fail; - CONSTRUCTOR_APPEND_ELT (n, idx, eltinit); - } - - if (!*non_constant_p) - { - init = build_constructor (atype, n); - TREE_CONSTANT (init) = true; - return init; - } - - fail: - vec_free (n); - return init; -} - -static tree -cxx_eval_vec_init (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - tree atype = TREE_TYPE (t); - tree init = VEC_INIT_EXPR_INIT (t); - tree r = cxx_eval_vec_init_1 (call, atype, init, - VEC_INIT_EXPR_VALUE_INIT (t), - allow_non_constant, addr, non_constant_p, overflow_p); - if (*non_constant_p) - return t; - else - return r; -} - -/* A less strict version of fold_indirect_ref_1, which requires cv-quals to - match. We want to be less strict for simple *& folding; if we have a - non-const temporary that we access through a const pointer, that should - work. We handle this here rather than change fold_indirect_ref_1 - because we're dealing with things like ADDR_EXPR of INTEGER_CST which - don't really make sense outside of constant expression evaluation. Also - we want to allow folding to COMPONENT_REF, which could cause trouble - with TBAA in fold_indirect_ref_1. - - Try to keep this function synced with fold_indirect_ref_1. */ - -static tree -cxx_fold_indirect_ref (location_t loc, tree type, tree op0, bool *empty_base) -{ - tree sub, subtype; - - sub = op0; - STRIP_NOPS (sub); - subtype = TREE_TYPE (sub); - if (!POINTER_TYPE_P (subtype)) - return NULL_TREE; - - if (TREE_CODE (sub) == ADDR_EXPR) - { - tree op = TREE_OPERAND (sub, 0); - tree optype = TREE_TYPE (op); - - /* *&CONST_DECL -> to the value of the const decl. */ - if (TREE_CODE (op) == CONST_DECL) - return DECL_INITIAL (op); - /* *&p => p; make sure to handle *&"str"[cst] here. */ - if (same_type_ignoring_top_level_qualifiers_p (optype, type)) - { - tree fop = fold_read_from_constant_string (op); - if (fop) - return fop; - else - return op; - } - /* *(foo *)&fooarray => fooarray[0] */ - else if (TREE_CODE (optype) == ARRAY_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (optype)))) - { - tree type_domain = TYPE_DOMAIN (optype); - tree min_val = size_zero_node; - if (type_domain && TYPE_MIN_VALUE (type_domain)) - min_val = TYPE_MIN_VALUE (type_domain); - return build4_loc (loc, ARRAY_REF, type, op, min_val, - NULL_TREE, NULL_TREE); - } - /* *(foo *)&complexfoo => __real__ complexfoo */ - else if (TREE_CODE (optype) == COMPLEX_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (optype)))) - return fold_build1_loc (loc, REALPART_EXPR, type, op); - /* *(foo *)&vectorfoo => BIT_FIELD_REF<vectorfoo,...> */ - else if (TREE_CODE (optype) == VECTOR_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (optype)))) - { - tree part_width = TYPE_SIZE (type); - tree index = bitsize_int (0); - return fold_build3_loc (loc, BIT_FIELD_REF, type, op, part_width, index); - } - /* Also handle conversion to an empty base class, which - is represented with a NOP_EXPR. */ - else if (is_empty_class (type) - && CLASS_TYPE_P (optype) - && DERIVED_FROM_P (type, optype)) - { - *empty_base = true; - return op; - } - /* *(foo *)&struct_with_foo_field => COMPONENT_REF */ - else if (RECORD_OR_UNION_TYPE_P (optype)) - { - tree field = TYPE_FIELDS (optype); - for (; field; field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL - && integer_zerop (byte_position (field)) - && (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (field), type))) - { - return fold_build3 (COMPONENT_REF, type, op, field, NULL_TREE); - break; - } - } - } - else if (TREE_CODE (sub) == POINTER_PLUS_EXPR - && TREE_CODE (TREE_OPERAND (sub, 1)) == INTEGER_CST) - { - tree op00 = TREE_OPERAND (sub, 0); - tree op01 = TREE_OPERAND (sub, 1); - - STRIP_NOPS (op00); - if (TREE_CODE (op00) == ADDR_EXPR) - { - tree op00type; - op00 = TREE_OPERAND (op00, 0); - op00type = TREE_TYPE (op00); - - /* ((foo*)&vectorfoo)[1] => BIT_FIELD_REF<vectorfoo,...> */ - if (TREE_CODE (op00type) == VECTOR_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (op00type)))) - { - HOST_WIDE_INT offset = tree_low_cst (op01, 0); - tree part_width = TYPE_SIZE (type); - unsigned HOST_WIDE_INT part_widthi = tree_low_cst (part_width, 0)/BITS_PER_UNIT; - unsigned HOST_WIDE_INT indexi = offset * BITS_PER_UNIT; - tree index = bitsize_int (indexi); - - if (offset/part_widthi <= TYPE_VECTOR_SUBPARTS (op00type)) - return fold_build3_loc (loc, - BIT_FIELD_REF, type, op00, - part_width, index); - - } - /* ((foo*)&complexfoo)[1] => __imag__ complexfoo */ - else if (TREE_CODE (op00type) == COMPLEX_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (op00type)))) - { - tree size = TYPE_SIZE_UNIT (type); - if (tree_int_cst_equal (size, op01)) - return fold_build1_loc (loc, IMAGPART_EXPR, type, op00); - } - /* ((foo *)&fooarray)[1] => fooarray[1] */ - else if (TREE_CODE (op00type) == ARRAY_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (op00type)))) - { - tree type_domain = TYPE_DOMAIN (op00type); - tree min_val = size_zero_node; - if (type_domain && TYPE_MIN_VALUE (type_domain)) - min_val = TYPE_MIN_VALUE (type_domain); - op01 = size_binop_loc (loc, EXACT_DIV_EXPR, op01, - TYPE_SIZE_UNIT (type)); - op01 = size_binop_loc (loc, PLUS_EXPR, op01, min_val); - return build4_loc (loc, ARRAY_REF, type, op00, op01, - NULL_TREE, NULL_TREE); - } - /* Also handle conversion to an empty base class, which - is represented with a NOP_EXPR. */ - else if (is_empty_class (type) - && CLASS_TYPE_P (op00type) - && DERIVED_FROM_P (type, op00type)) - { - *empty_base = true; - return op00; - } - /* ((foo *)&struct_with_foo_field)[1] => COMPONENT_REF */ - else if (RECORD_OR_UNION_TYPE_P (op00type)) - { - tree field = TYPE_FIELDS (op00type); - for (; field; field = DECL_CHAIN (field)) - if (TREE_CODE (field) == FIELD_DECL - && tree_int_cst_equal (byte_position (field), op01) - && (same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (field), type))) - { - return fold_build3 (COMPONENT_REF, type, op00, - field, NULL_TREE); - break; - } - } - } - } - /* *(foo *)fooarrptr => (*fooarrptr)[0] */ - else if (TREE_CODE (TREE_TYPE (subtype)) == ARRAY_TYPE - && (same_type_ignoring_top_level_qualifiers_p - (type, TREE_TYPE (TREE_TYPE (subtype))))) - { - tree type_domain; - tree min_val = size_zero_node; - tree newsub = cxx_fold_indirect_ref (loc, TREE_TYPE (subtype), sub, NULL); - if (newsub) - sub = newsub; - else - sub = build1_loc (loc, INDIRECT_REF, TREE_TYPE (subtype), sub); - type_domain = TYPE_DOMAIN (TREE_TYPE (sub)); - if (type_domain && TYPE_MIN_VALUE (type_domain)) - min_val = TYPE_MIN_VALUE (type_domain); - return build4_loc (loc, ARRAY_REF, type, sub, min_val, NULL_TREE, - NULL_TREE); - } - - return NULL_TREE; -} - -static tree -cxx_eval_indirect_ref (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - tree orig_op0 = TREE_OPERAND (t, 0); - tree op0 = cxx_eval_constant_expression (call, orig_op0, allow_non_constant, - /*addr*/false, non_constant_p, overflow_p); - bool empty_base = false; - tree r; - - /* Don't VERIFY_CONSTANT here. */ - if (*non_constant_p) - return t; - - r = cxx_fold_indirect_ref (EXPR_LOCATION (t), TREE_TYPE (t), op0, - &empty_base); - - if (r) - r = cxx_eval_constant_expression (call, r, allow_non_constant, - addr, non_constant_p, overflow_p); - else - { - tree sub = op0; - STRIP_NOPS (sub); - if (TREE_CODE (sub) == POINTER_PLUS_EXPR) - { - sub = TREE_OPERAND (sub, 0); - STRIP_NOPS (sub); - } - if (TREE_CODE (sub) == ADDR_EXPR) - { - /* We couldn't fold to a constant value. Make sure it's not - something we should have been able to fold. */ - gcc_assert (!same_type_ignoring_top_level_qualifiers_p - (TREE_TYPE (TREE_TYPE (sub)), TREE_TYPE (t))); - /* DR 1188 says we don't have to deal with this. */ - if (!allow_non_constant) - error ("accessing value of %qE through a %qT glvalue in a " - "constant expression", build_fold_indirect_ref (sub), - TREE_TYPE (t)); - *non_constant_p = true; - return t; - } - } - - /* If we're pulling out the value of an empty base, make sure - that the whole object is constant and then return an empty - CONSTRUCTOR. */ - if (empty_base) - { - VERIFY_CONSTANT (r); - r = build_constructor (TREE_TYPE (t), NULL); - TREE_CONSTANT (r) = true; - } - - if (r == NULL_TREE) - { - if (addr && op0 != orig_op0) - return build1 (INDIRECT_REF, TREE_TYPE (t), op0); - if (!addr) - VERIFY_CONSTANT (t); - return t; - } - return r; -} - -/* Complain about R, a VAR_DECL, not being usable in a constant expression. - Shared between potential_constant_expression and - cxx_eval_constant_expression. */ - -static void -non_const_var_error (tree r) -{ - tree type = TREE_TYPE (r); - error ("the value of %qD is not usable in a constant " - "expression", r); - /* Avoid error cascade. */ - if (DECL_INITIAL (r) == error_mark_node) - return; - if (DECL_DECLARED_CONSTEXPR_P (r)) - inform (DECL_SOURCE_LOCATION (r), - "%qD used in its own initializer", r); - else if (INTEGRAL_OR_ENUMERATION_TYPE_P (type)) - { - if (!CP_TYPE_CONST_P (type)) - inform (DECL_SOURCE_LOCATION (r), - "%q#D is not const", r); - else if (CP_TYPE_VOLATILE_P (type)) - inform (DECL_SOURCE_LOCATION (r), - "%q#D is volatile", r); - else if (!DECL_INITIAL (r) - || !TREE_CONSTANT (DECL_INITIAL (r))) - inform (DECL_SOURCE_LOCATION (r), - "%qD was not initialized with a constant " - "expression", r); - else - gcc_unreachable (); - } - else - { - if (cxx_dialect >= cxx0x && !DECL_DECLARED_CONSTEXPR_P (r)) - inform (DECL_SOURCE_LOCATION (r), - "%qD was not declared %<constexpr%>", r); - else - inform (DECL_SOURCE_LOCATION (r), - "%qD does not have integral or enumeration type", - r); - } -} - -/* Evaluate VEC_PERM_EXPR (v1, v2, mask). */ -static tree -cxx_eval_vec_perm_expr (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - int i; - tree args[3]; - tree val; - tree elttype = TREE_TYPE (t); - - for (i = 0; i < 3; i++) - { - args[i] = cxx_eval_constant_expression (call, TREE_OPERAND (t, i), - allow_non_constant, addr, - non_constant_p, overflow_p); - if (*non_constant_p) - goto fail; - } - - gcc_assert (TREE_CODE (TREE_TYPE (args[0])) == VECTOR_TYPE); - gcc_assert (TREE_CODE (TREE_TYPE (args[1])) == VECTOR_TYPE); - gcc_assert (TREE_CODE (TREE_TYPE (args[2])) == VECTOR_TYPE); - - val = fold_ternary_loc (EXPR_LOCATION (t), VEC_PERM_EXPR, elttype, - args[0], args[1], args[2]); - if (val != NULL_TREE) - return val; - - fail: - return t; -} - -/* Attempt to reduce the expression T to a constant value. - On failure, issue diagnostic and return error_mark_node. */ -/* FIXME unify with c_fully_fold */ - -static tree -cxx_eval_constant_expression (const constexpr_call *call, tree t, - bool allow_non_constant, bool addr, - bool *non_constant_p, bool *overflow_p) -{ - tree r = t; - - if (t == error_mark_node) - { - *non_constant_p = true; - return t; - } - if (CONSTANT_CLASS_P (t)) - { - if (TREE_CODE (t) == PTRMEM_CST) - t = cplus_expand_constant (t); - else if (TREE_OVERFLOW (t) && (!flag_permissive || allow_non_constant)) - *overflow_p = true; - return t; - } - if (TREE_CODE (t) != NOP_EXPR - && reduced_constant_expression_p (t)) - return fold (t); - - switch (TREE_CODE (t)) - { - case VAR_DECL: - if (addr) - return t; - /* else fall through. */ - case CONST_DECL: - r = integral_constant_value (t); - if (TREE_CODE (r) == TARGET_EXPR - && TREE_CODE (TARGET_EXPR_INITIAL (r)) == CONSTRUCTOR) - r = TARGET_EXPR_INITIAL (r); - if (DECL_P (r)) - { - if (!allow_non_constant) - non_const_var_error (r); - *non_constant_p = true; - } - break; - - case FUNCTION_DECL: - case TEMPLATE_DECL: - case LABEL_DECL: - return t; - - case PARM_DECL: - if (call && DECL_CONTEXT (t) == call->fundef->decl) - { - if (DECL_ARTIFICIAL (t) && DECL_CONSTRUCTOR_P (DECL_CONTEXT (t))) - { - if (!allow_non_constant) - sorry ("use of the value of the object being constructed " - "in a constant expression"); - *non_constant_p = true; - } - else - r = lookup_parameter_binding (call, t); - } - else if (addr) - /* Defer in case this is only used for its type. */; - else - { - if (!allow_non_constant) - error ("%qE is not a constant expression", t); - *non_constant_p = true; - } - break; - - case CALL_EXPR: - case AGGR_INIT_EXPR: - r = cxx_eval_call_expression (call, t, allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case TARGET_EXPR: - if (!literal_type_p (TREE_TYPE (t))) - { - if (!allow_non_constant) - { - error ("temporary of non-literal type %qT in a " - "constant expression", TREE_TYPE (t)); - explain_non_literal_class (TREE_TYPE (t)); - } - *non_constant_p = true; - break; - } - /* else fall through. */ - case INIT_EXPR: - /* Pass false for 'addr' because these codes indicate - initialization of a temporary. */ - r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1), - allow_non_constant, false, - non_constant_p, overflow_p); - if (!*non_constant_p) - /* Adjust the type of the result to the type of the temporary. */ - r = adjust_temp_type (TREE_TYPE (t), r); - break; - - case SCOPE_REF: - r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 1), - allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case RETURN_EXPR: - case NON_LVALUE_EXPR: - case TRY_CATCH_EXPR: - case CLEANUP_POINT_EXPR: - case MUST_NOT_THROW_EXPR: - case SAVE_EXPR: - r = cxx_eval_constant_expression (call, TREE_OPERAND (t, 0), - allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - /* These differ from cxx_eval_unary_expression in that this doesn't - check for a constant operand or result; an address can be - constant without its operand being, and vice versa. */ - case INDIRECT_REF: - r = cxx_eval_indirect_ref (call, t, allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case ADDR_EXPR: - { - tree oldop = TREE_OPERAND (t, 0); - tree op = cxx_eval_constant_expression (call, oldop, - allow_non_constant, - /*addr*/true, - non_constant_p, overflow_p); - /* Don't VERIFY_CONSTANT here. */ - if (*non_constant_p) - return t; - /* This function does more aggressive folding than fold itself. */ - r = build_fold_addr_expr_with_type (op, TREE_TYPE (t)); - if (TREE_CODE (r) == ADDR_EXPR && TREE_OPERAND (r, 0) == oldop) - return t; - break; - } - - case REALPART_EXPR: - case IMAGPART_EXPR: - case CONJ_EXPR: - case FIX_TRUNC_EXPR: - case FLOAT_EXPR: - case NEGATE_EXPR: - case ABS_EXPR: - case BIT_NOT_EXPR: - case TRUTH_NOT_EXPR: - case FIXED_CONVERT_EXPR: - r = cxx_eval_unary_expression (call, t, allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case SIZEOF_EXPR: - if (SIZEOF_EXPR_TYPE_P (t)) - r = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (t, 0)), - SIZEOF_EXPR, false); - else if (TYPE_P (TREE_OPERAND (t, 0))) - r = cxx_sizeof_or_alignof_type (TREE_OPERAND (t, 0), SIZEOF_EXPR, - false); - else - r = cxx_sizeof_or_alignof_expr (TREE_OPERAND (t, 0), SIZEOF_EXPR, - false); - if (r == error_mark_node) - r = size_one_node; - VERIFY_CONSTANT (r); - break; - - case COMPOUND_EXPR: - { - /* check_return_expr sometimes wraps a TARGET_EXPR in a - COMPOUND_EXPR; don't get confused. Also handle EMPTY_CLASS_EXPR - introduced by build_call_a. */ - tree op0 = TREE_OPERAND (t, 0); - tree op1 = TREE_OPERAND (t, 1); - STRIP_NOPS (op1); - if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0)) - || TREE_CODE (op1) == EMPTY_CLASS_EXPR) - r = cxx_eval_constant_expression (call, op0, allow_non_constant, - addr, non_constant_p, overflow_p); - else - { - /* Check that the LHS is constant and then discard it. */ - cxx_eval_constant_expression (call, op0, allow_non_constant, - false, non_constant_p, overflow_p); - op1 = TREE_OPERAND (t, 1); - r = cxx_eval_constant_expression (call, op1, allow_non_constant, - addr, non_constant_p, overflow_p); - } - } - break; - - case POINTER_PLUS_EXPR: - case PLUS_EXPR: - case MINUS_EXPR: - case MULT_EXPR: - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case TRUNC_MOD_EXPR: - case CEIL_MOD_EXPR: - case ROUND_MOD_EXPR: - case RDIV_EXPR: - case EXACT_DIV_EXPR: - case MIN_EXPR: - case MAX_EXPR: - case LSHIFT_EXPR: - case RSHIFT_EXPR: - case LROTATE_EXPR: - case RROTATE_EXPR: - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - case BIT_AND_EXPR: - case TRUTH_XOR_EXPR: - case LT_EXPR: - case LE_EXPR: - case GT_EXPR: - case GE_EXPR: - case EQ_EXPR: - case NE_EXPR: - case UNORDERED_EXPR: - case ORDERED_EXPR: - case UNLT_EXPR: - case UNLE_EXPR: - case UNGT_EXPR: - case UNGE_EXPR: - case UNEQ_EXPR: - case RANGE_EXPR: - case COMPLEX_EXPR: - r = cxx_eval_binary_expression (call, t, allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - /* fold can introduce non-IF versions of these; still treat them as - short-circuiting. */ - case TRUTH_AND_EXPR: - case TRUTH_ANDIF_EXPR: - r = cxx_eval_logical_expression (call, t, boolean_false_node, - boolean_true_node, - allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case TRUTH_OR_EXPR: - case TRUTH_ORIF_EXPR: - r = cxx_eval_logical_expression (call, t, boolean_true_node, - boolean_false_node, - allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case ARRAY_REF: - r = cxx_eval_array_reference (call, t, allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case COMPONENT_REF: - r = cxx_eval_component_reference (call, t, allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case BIT_FIELD_REF: - r = cxx_eval_bit_field_ref (call, t, allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case COND_EXPR: - case VEC_COND_EXPR: - r = cxx_eval_conditional_expression (call, t, allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case CONSTRUCTOR: - r = cxx_eval_bare_aggregate (call, t, allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case VEC_INIT_EXPR: - /* We can get this in a defaulted constructor for a class with a - non-static data member of array type. Either the initializer will - be NULL, meaning default-initialization, or it will be an lvalue - or xvalue of the same type, meaning direct-initialization from the - corresponding member. */ - r = cxx_eval_vec_init (call, t, allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case VEC_PERM_EXPR: - r = cxx_eval_vec_perm_expr (call, t, allow_non_constant, addr, - non_constant_p, overflow_p); - break; - - case CONVERT_EXPR: - case VIEW_CONVERT_EXPR: - case NOP_EXPR: - { - tree oldop = TREE_OPERAND (t, 0); - tree op = cxx_eval_constant_expression (call, oldop, - allow_non_constant, addr, - non_constant_p, overflow_p); - if (*non_constant_p) - return t; - if (op == oldop) - /* We didn't fold at the top so we could check for ptr-int - conversion. */ - return fold (t); - r = fold_build1 (TREE_CODE (t), TREE_TYPE (t), op); - /* Conversion of an out-of-range value has implementation-defined - behavior; the language considers it different from arithmetic - overflow, which is undefined. */ - if (TREE_OVERFLOW_P (r) && !TREE_OVERFLOW_P (op)) - TREE_OVERFLOW (r) = false; - } - break; - - case EMPTY_CLASS_EXPR: - /* This is good enough for a function argument that might not get - used, and they can't do anything with it, so just return it. */ - return t; - - case LAMBDA_EXPR: - case PREINCREMENT_EXPR: - case POSTINCREMENT_EXPR: - case PREDECREMENT_EXPR: - case POSTDECREMENT_EXPR: - case NEW_EXPR: - case VEC_NEW_EXPR: - case DELETE_EXPR: - case VEC_DELETE_EXPR: - case THROW_EXPR: - case MODIFY_EXPR: - case MODOP_EXPR: - /* GCC internal stuff. */ - case VA_ARG_EXPR: - case OBJ_TYPE_REF: - case WITH_CLEANUP_EXPR: - case STATEMENT_LIST: - case BIND_EXPR: - case NON_DEPENDENT_EXPR: - case BASELINK: - case EXPR_STMT: - case OFFSET_REF: - if (!allow_non_constant) - error_at (EXPR_LOC_OR_HERE (t), - "expression %qE is not a constant-expression", t); - *non_constant_p = true; - break; - - default: - internal_error ("unexpected expression %qE of kind %s", t, - tree_code_name[TREE_CODE (t)]); - *non_constant_p = true; - break; - } - - if (r == error_mark_node) - *non_constant_p = true; - - if (*non_constant_p) - return t; - else - return r; -} - -static tree -cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant) -{ - bool non_constant_p = false; - bool overflow_p = false; - tree r = cxx_eval_constant_expression (NULL, t, allow_non_constant, - false, &non_constant_p, &overflow_p); - - verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p); - - if (TREE_CODE (t) != CONSTRUCTOR - && cp_has_mutable_p (TREE_TYPE (t))) - { - /* We allow a mutable type if the original expression was a - CONSTRUCTOR so that we can do aggregate initialization of - constexpr variables. */ - if (!allow_non_constant) - error ("%qT cannot be the type of a complete constant expression " - "because it has mutable sub-objects", TREE_TYPE (t)); - non_constant_p = true; - } - - /* Technically we should check this for all subexpressions, but that - runs into problems with our internal representation of pointer - subtraction and the 5.19 rules are still in flux. */ - if (CONVERT_EXPR_CODE_P (TREE_CODE (r)) - && ARITHMETIC_TYPE_P (TREE_TYPE (r)) - && TREE_CODE (TREE_OPERAND (r, 0)) == ADDR_EXPR) - { - if (!allow_non_constant) - error ("conversion from pointer type %qT " - "to arithmetic type %qT in a constant-expression", - TREE_TYPE (TREE_OPERAND (r, 0)), TREE_TYPE (r)); - non_constant_p = true; - } - - if (!non_constant_p && overflow_p) - non_constant_p = true; - - if (non_constant_p && !allow_non_constant) - return error_mark_node; - else if (non_constant_p && TREE_CONSTANT (r)) - { - /* This isn't actually constant, so unset TREE_CONSTANT. */ - if (EXPR_P (r)) - r = copy_node (r); - else if (TREE_CODE (r) == CONSTRUCTOR) - r = build1 (VIEW_CONVERT_EXPR, TREE_TYPE (r), r); - else - r = build_nop (TREE_TYPE (r), r); - TREE_CONSTANT (r) = false; - } - else if (non_constant_p || r == t) - return t; - - if (TREE_CODE (r) == CONSTRUCTOR && CLASS_TYPE_P (TREE_TYPE (r))) - { - if (TREE_CODE (t) == TARGET_EXPR - && TARGET_EXPR_INITIAL (t) == r) - return t; - else - { - r = get_target_expr (r); - TREE_CONSTANT (r) = true; - return r; - } - } - else - return r; -} - -/* Returns true if T is a valid subexpression of a constant expression, - even if it isn't itself a constant expression. */ - -bool -is_sub_constant_expr (tree t) -{ - bool non_constant_p = false; - bool overflow_p = false; - cxx_eval_constant_expression (NULL, t, true, false, &non_constant_p, - &overflow_p); - return !non_constant_p && !overflow_p; -} - -/* If T represents a constant expression returns its reduced value. - Otherwise return error_mark_node. If T is dependent, then - return NULL. */ - -tree -cxx_constant_value (tree t) -{ - return cxx_eval_outermost_constant_expr (t, false); -} - -/* If T is a constant expression, returns its reduced value. - Otherwise, if T does not have TREE_CONSTANT set, returns T. - Otherwise, returns a version of T without TREE_CONSTANT. */ - -tree -maybe_constant_value (tree t) -{ - tree r; - - if (type_dependent_expression_p (t) - || type_unknown_p (t) - || BRACE_ENCLOSED_INITIALIZER_P (t) - || !potential_constant_expression (t) - || value_dependent_expression_p (t)) - { - if (TREE_OVERFLOW_P (t)) - { - t = build_nop (TREE_TYPE (t), t); - TREE_CONSTANT (t) = false; - } - return t; - } - - r = cxx_eval_outermost_constant_expr (t, true); -#ifdef ENABLE_CHECKING - /* cp_tree_equal looks through NOPs, so allow them. */ - gcc_assert (r == t - || CONVERT_EXPR_P (t) - || (TREE_CONSTANT (t) && !TREE_CONSTANT (r)) - || !cp_tree_equal (r, t)); -#endif - return r; -} - -/* Like maybe_constant_value, but returns a CONSTRUCTOR directly, rather - than wrapped in a TARGET_EXPR. */ - -tree -maybe_constant_init (tree t) -{ - t = maybe_constant_value (t); - if (TREE_CODE (t) == TARGET_EXPR) - { - tree init = TARGET_EXPR_INITIAL (t); - if (TREE_CODE (init) == CONSTRUCTOR) - t = init; - } - return t; -} - -#if 0 -/* FIXME see ADDR_EXPR section in potential_constant_expression_1. */ -/* Return true if the object referred to by REF has automatic or thread - local storage. */ - -enum { ck_ok, ck_bad, ck_unknown }; -static int -check_automatic_or_tls (tree ref) -{ - enum machine_mode mode; - HOST_WIDE_INT bitsize, bitpos; - tree offset; - int volatilep = 0, unsignedp = 0; - tree decl = get_inner_reference (ref, &bitsize, &bitpos, &offset, - &mode, &unsignedp, &volatilep, false); - duration_kind dk; - - /* If there isn't a decl in the middle, we don't know the linkage here, - and this isn't a constant expression anyway. */ - if (!DECL_P (decl)) - return ck_unknown; - dk = decl_storage_duration (decl); - return (dk == dk_auto || dk == dk_thread) ? ck_bad : ck_ok; -} -#endif - -/* Return true if T denotes a potentially constant expression. Issue - diagnostic as appropriate under control of FLAGS. If WANT_RVAL is true, - an lvalue-rvalue conversion is implied. - - C++0x [expr.const] used to say - - 6 An expression is a potential constant expression if it is - a constant expression where all occurences of function - parameters are replaced by arbitrary constant expressions - of the appropriate type. - - 2 A conditional expression is a constant expression unless it - involves one of the following as a potentially evaluated - subexpression (3.2), but subexpressions of logical AND (5.14), - logical OR (5.15), and conditional (5.16) operations that are - not evaluated are not considered. */ - -static bool -potential_constant_expression_1 (tree t, bool want_rval, tsubst_flags_t flags) -{ - enum { any = false, rval = true }; - int i; - tree tmp; - - if (t == error_mark_node) - return false; - if (t == NULL_TREE) - return true; - if (TREE_THIS_VOLATILE (t)) - { - if (flags & tf_error) - error ("expression %qE has side-effects", t); - return false; - } - if (CONSTANT_CLASS_P (t)) - return true; - - switch (TREE_CODE (t)) - { - case FUNCTION_DECL: - case BASELINK: - case TEMPLATE_DECL: - case OVERLOAD: - case TEMPLATE_ID_EXPR: - case LABEL_DECL: - case CONST_DECL: - case SIZEOF_EXPR: - case ALIGNOF_EXPR: - case OFFSETOF_EXPR: - case NOEXCEPT_EXPR: - case TEMPLATE_PARM_INDEX: - case TRAIT_EXPR: - case IDENTIFIER_NODE: - case USERDEF_LITERAL: - /* We can see a FIELD_DECL in a pointer-to-member expression. */ - case FIELD_DECL: - case PARM_DECL: - case USING_DECL: - return true; - - case AGGR_INIT_EXPR: - case CALL_EXPR: - /* -- an invocation of a function other than a constexpr function - or a constexpr constructor. */ - { - tree fun = get_function_named_in_call (t); - const int nargs = call_expr_nargs (t); - i = 0; - - if (is_overloaded_fn (fun)) - { - if (TREE_CODE (fun) == FUNCTION_DECL) - { - if (builtin_valid_in_constant_expr_p (fun)) - return true; - if (!DECL_DECLARED_CONSTEXPR_P (fun) - /* Allow any built-in function; if the expansion - isn't constant, we'll deal with that then. */ - && !is_builtin_fn (fun)) - { - if (flags & tf_error) - { - error_at (EXPR_LOC_OR_HERE (t), - "call to non-constexpr function %qD", fun); - explain_invalid_constexpr_fn (fun); - } - return false; - } - /* A call to a non-static member function takes the address - of the object as the first argument. But in a constant - expression the address will be folded away, so look - through it now. */ - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (fun) - && !DECL_CONSTRUCTOR_P (fun)) - { - tree x = get_nth_callarg (t, 0); - if (is_this_parameter (x)) - { - if (DECL_CONSTRUCTOR_P (DECL_CONTEXT (x))) - { - if (flags & tf_error) - sorry ("calling a member function of the " - "object being constructed in a constant " - "expression"); - return false; - } - /* Otherwise OK. */; - } - else if (!potential_constant_expression_1 (x, rval, flags)) - return false; - i = 1; - } - } - else - { - if (!potential_constant_expression_1 (fun, true, flags)) - return false; - fun = get_first_fn (fun); - } - /* Skip initial arguments to base constructors. */ - if (DECL_BASE_CONSTRUCTOR_P (fun)) - i = num_artificial_parms_for (fun); - fun = DECL_ORIGIN (fun); - } - else - { - if (potential_constant_expression_1 (fun, rval, flags)) - /* Might end up being a constant function pointer. */; - else - return false; - } - for (; i < nargs; ++i) - { - tree x = get_nth_callarg (t, i); - if (!potential_constant_expression_1 (x, rval, flags)) - return false; - } - return true; - } - - case NON_LVALUE_EXPR: - /* -- an lvalue-to-rvalue conversion (4.1) unless it is applied to - -- an lvalue of integral type that refers to a non-volatile - const variable or static data member initialized with - constant expressions, or - - -- an lvalue of literal type that refers to non-volatile - object defined with constexpr, or that refers to a - sub-object of such an object; */ - return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval, flags); - - case VAR_DECL: - if (want_rval && !decl_constant_var_p (t) - && !dependent_type_p (TREE_TYPE (t))) - { - if (flags & tf_error) - non_const_var_error (t); - return false; - } - return true; - - case NOP_EXPR: - case CONVERT_EXPR: - case VIEW_CONVERT_EXPR: - /* -- a reinterpret_cast. FIXME not implemented, and this rule - may change to something more specific to type-punning (DR 1312). */ - { - tree from = TREE_OPERAND (t, 0); - return (potential_constant_expression_1 - (from, TREE_CODE (t) != VIEW_CONVERT_EXPR, flags)); - } - - case ADDR_EXPR: - /* -- a unary operator & that is applied to an lvalue that - designates an object with thread or automatic storage - duration; */ - t = TREE_OPERAND (t, 0); -#if 0 - /* FIXME adjust when issue 1197 is fully resolved. For now don't do - any checking here, as we might dereference the pointer later. If - we remove this code, also remove check_automatic_or_tls. */ - i = check_automatic_or_tls (t); - if (i == ck_ok) - return true; - if (i == ck_bad) - { - if (flags & tf_error) - error ("address-of an object %qE with thread local or " - "automatic storage is not a constant expression", t); - return false; - } -#endif - return potential_constant_expression_1 (t, any, flags); - - case COMPONENT_REF: - case BIT_FIELD_REF: - case ARROW_EXPR: - case OFFSET_REF: - /* -- a class member access unless its postfix-expression is - of literal type or of pointer to literal type. */ - /* This test would be redundant, as it follows from the - postfix-expression being a potential constant expression. */ - return potential_constant_expression_1 (TREE_OPERAND (t, 0), - want_rval, flags); - - case EXPR_PACK_EXPANSION: - return potential_constant_expression_1 (PACK_EXPANSION_PATTERN (t), - want_rval, flags); - - case INDIRECT_REF: - { - tree x = TREE_OPERAND (t, 0); - STRIP_NOPS (x); - if (is_this_parameter (x)) - { - if (want_rval && DECL_CONTEXT (x) - && DECL_CONSTRUCTOR_P (DECL_CONTEXT (x))) - { - if (flags & tf_error) - sorry ("use of the value of the object being constructed " - "in a constant expression"); - return false; - } - return true; - } - return potential_constant_expression_1 (x, rval, flags); - } - - case LAMBDA_EXPR: - case DYNAMIC_CAST_EXPR: - case PSEUDO_DTOR_EXPR: - case PREINCREMENT_EXPR: - case POSTINCREMENT_EXPR: - case PREDECREMENT_EXPR: - case POSTDECREMENT_EXPR: - case NEW_EXPR: - case VEC_NEW_EXPR: - case DELETE_EXPR: - case VEC_DELETE_EXPR: - case THROW_EXPR: - case MODIFY_EXPR: - case MODOP_EXPR: - /* GCC internal stuff. */ - case VA_ARG_EXPR: - case OBJ_TYPE_REF: - case WITH_CLEANUP_EXPR: - case CLEANUP_POINT_EXPR: - case MUST_NOT_THROW_EXPR: - case TRY_CATCH_EXPR: - case STATEMENT_LIST: - /* Don't bother trying to define a subset of statement-expressions to - be constant-expressions, at least for now. */ - case STMT_EXPR: - case EXPR_STMT: - case BIND_EXPR: - case TRANSACTION_EXPR: - case IF_STMT: - case DO_STMT: - case FOR_STMT: - case WHILE_STMT: - if (flags & tf_error) - error ("expression %qE is not a constant-expression", t); - return false; - - case TYPEID_EXPR: - /* -- a typeid expression whose operand is of polymorphic - class type; */ - { - tree e = TREE_OPERAND (t, 0); - if (!TYPE_P (e) && !type_dependent_expression_p (e) - && TYPE_POLYMORPHIC_P (TREE_TYPE (e))) - { - if (flags & tf_error) - error ("typeid-expression is not a constant expression " - "because %qE is of polymorphic type", e); - return false; - } - return true; - } - - case MINUS_EXPR: - /* -- a subtraction where both operands are pointers. */ - if (TYPE_PTR_P (TREE_OPERAND (t, 0)) - && TYPE_PTR_P (TREE_OPERAND (t, 1))) - { - if (flags & tf_error) - error ("difference of two pointer expressions is not " - "a constant expression"); - return false; - } - want_rval = true; - goto binary; - - case LT_EXPR: - case LE_EXPR: - case GT_EXPR: - case GE_EXPR: - case EQ_EXPR: - case NE_EXPR: - /* -- a relational or equality operator where at least - one of the operands is a pointer. */ - if (TYPE_PTR_P (TREE_OPERAND (t, 0)) - || TYPE_PTR_P (TREE_OPERAND (t, 1))) - { - if (flags & tf_error) - error ("pointer comparison expression is not a " - "constant expression"); - return false; - } - want_rval = true; - goto binary; - - case BIT_NOT_EXPR: - /* A destructor. */ - if (TYPE_P (TREE_OPERAND (t, 0))) - return true; - /* else fall through. */ - - case REALPART_EXPR: - case IMAGPART_EXPR: - case CONJ_EXPR: - case SAVE_EXPR: - case FIX_TRUNC_EXPR: - case FLOAT_EXPR: - case NEGATE_EXPR: - case ABS_EXPR: - case TRUTH_NOT_EXPR: - case FIXED_CONVERT_EXPR: - case UNARY_PLUS_EXPR: - return potential_constant_expression_1 (TREE_OPERAND (t, 0), rval, - flags); - - case CAST_EXPR: - case CONST_CAST_EXPR: - case STATIC_CAST_EXPR: - case REINTERPRET_CAST_EXPR: - case IMPLICIT_CONV_EXPR: - if (cxx_dialect < cxx0x - && !dependent_type_p (TREE_TYPE (t)) - && !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (t))) - /* In C++98, a conversion to non-integral type can't be part of a - constant expression. */ - { - if (flags & tf_error) - error ("cast to non-integral type %qT in a constant expression", - TREE_TYPE (t)); - return false; - } - - return (potential_constant_expression_1 - (TREE_OPERAND (t, 0), - TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE, flags)); - - case PAREN_EXPR: - case NON_DEPENDENT_EXPR: - /* For convenience. */ - case RETURN_EXPR: - return potential_constant_expression_1 (TREE_OPERAND (t, 0), - want_rval, flags); - - case SCOPE_REF: - return potential_constant_expression_1 (TREE_OPERAND (t, 1), - want_rval, flags); - - case TARGET_EXPR: - if (!literal_type_p (TREE_TYPE (t))) - { - if (flags & tf_error) - { - error ("temporary of non-literal type %qT in a " - "constant expression", TREE_TYPE (t)); - explain_non_literal_class (TREE_TYPE (t)); - } - return false; - } - case INIT_EXPR: - return potential_constant_expression_1 (TREE_OPERAND (t, 1), - rval, flags); - - case CONSTRUCTOR: - { - vec<constructor_elt, va_gc> *v = CONSTRUCTOR_ELTS (t); - constructor_elt *ce; - for (i = 0; vec_safe_iterate (v, i, &ce); ++i) - if (!potential_constant_expression_1 (ce->value, want_rval, flags)) - return false; - return true; - } - - case TREE_LIST: - { - gcc_assert (TREE_PURPOSE (t) == NULL_TREE - || DECL_P (TREE_PURPOSE (t))); - if (!potential_constant_expression_1 (TREE_VALUE (t), want_rval, - flags)) - return false; - if (TREE_CHAIN (t) == NULL_TREE) - return true; - return potential_constant_expression_1 (TREE_CHAIN (t), want_rval, - flags); - } - - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case TRUNC_MOD_EXPR: - case CEIL_MOD_EXPR: - case ROUND_MOD_EXPR: - { - tree denom = TREE_OPERAND (t, 1); - if (!potential_constant_expression_1 (denom, rval, flags)) - return false; - /* We can't call cxx_eval_outermost_constant_expr on an expression - that hasn't been through fold_non_dependent_expr yet. */ - if (!processing_template_decl) - denom = cxx_eval_outermost_constant_expr (denom, true); - if (integer_zerop (denom)) - { - if (flags & tf_error) - error ("division by zero is not a constant-expression"); - return false; - } - else - { - want_rval = true; - return potential_constant_expression_1 (TREE_OPERAND (t, 0), - want_rval, flags); - } - } - - case COMPOUND_EXPR: - { - /* check_return_expr sometimes wraps a TARGET_EXPR in a - COMPOUND_EXPR; don't get confused. Also handle EMPTY_CLASS_EXPR - introduced by build_call_a. */ - tree op0 = TREE_OPERAND (t, 0); - tree op1 = TREE_OPERAND (t, 1); - STRIP_NOPS (op1); - if ((TREE_CODE (op0) == TARGET_EXPR && op1 == TARGET_EXPR_SLOT (op0)) - || TREE_CODE (op1) == EMPTY_CLASS_EXPR) - return potential_constant_expression_1 (op0, want_rval, flags); - else - goto binary; - } - - /* If the first operand is the non-short-circuit constant, look at - the second operand; otherwise we only care about the first one for - potentiality. */ - case TRUTH_AND_EXPR: - case TRUTH_ANDIF_EXPR: - tmp = boolean_true_node; - goto truth; - case TRUTH_OR_EXPR: - case TRUTH_ORIF_EXPR: - tmp = boolean_false_node; - truth: - { - tree op = TREE_OPERAND (t, 0); - if (!potential_constant_expression_1 (op, rval, flags)) - return false; - if (!processing_template_decl) - op = cxx_eval_outermost_constant_expr (op, true); - if (tree_int_cst_equal (op, tmp)) - return potential_constant_expression_1 (TREE_OPERAND (t, 1), rval, flags); - else - return true; - } - - case PLUS_EXPR: - case MULT_EXPR: - case POINTER_PLUS_EXPR: - case RDIV_EXPR: - case EXACT_DIV_EXPR: - case MIN_EXPR: - case MAX_EXPR: - case LSHIFT_EXPR: - case RSHIFT_EXPR: - case LROTATE_EXPR: - case RROTATE_EXPR: - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - case BIT_AND_EXPR: - case TRUTH_XOR_EXPR: - case UNORDERED_EXPR: - case ORDERED_EXPR: - case UNLT_EXPR: - case UNLE_EXPR: - case UNGT_EXPR: - case UNGE_EXPR: - case UNEQ_EXPR: - case LTGT_EXPR: - case RANGE_EXPR: - case COMPLEX_EXPR: - want_rval = true; - /* Fall through. */ - case ARRAY_REF: - case ARRAY_RANGE_REF: - case MEMBER_REF: - case DOTSTAR_EXPR: - binary: - for (i = 0; i < 2; ++i) - if (!potential_constant_expression_1 (TREE_OPERAND (t, i), - want_rval, flags)) - return false; - return true; - - case FMA_EXPR: - case VEC_PERM_EXPR: - for (i = 0; i < 3; ++i) - if (!potential_constant_expression_1 (TREE_OPERAND (t, i), - true, flags)) - return false; - return true; - - case COND_EXPR: - case VEC_COND_EXPR: - /* If the condition is a known constant, we know which of the legs we - care about; otherwise we only require that the condition and - either of the legs be potentially constant. */ - tmp = TREE_OPERAND (t, 0); - if (!potential_constant_expression_1 (tmp, rval, flags)) - return false; - if (!processing_template_decl) - tmp = cxx_eval_outermost_constant_expr (tmp, true); - if (integer_zerop (tmp)) - return potential_constant_expression_1 (TREE_OPERAND (t, 2), - want_rval, flags); - else if (TREE_CODE (tmp) == INTEGER_CST) - return potential_constant_expression_1 (TREE_OPERAND (t, 1), - want_rval, flags); - for (i = 1; i < 3; ++i) - if (potential_constant_expression_1 (TREE_OPERAND (t, i), - want_rval, tf_none)) - return true; - if (flags & tf_error) - error ("expression %qE is not a constant-expression", t); - return false; - - case VEC_INIT_EXPR: - if (VEC_INIT_EXPR_IS_CONSTEXPR (t)) - return true; - if (flags & tf_error) - { - error ("non-constant array initialization"); - diagnose_non_constexpr_vec_init (t); - } - return false; - - default: - if (objc_is_property_ref (t)) - return false; - - sorry ("unexpected AST of kind %s", tree_code_name[TREE_CODE (t)]); - gcc_unreachable(); - return false; - } -} - -/* The main entry point to the above. */ - -bool -potential_constant_expression (tree t) -{ - return potential_constant_expression_1 (t, false, tf_none); -} - -/* As above, but require a constant rvalue. */ - -bool -potential_rvalue_constant_expression (tree t) -{ - return potential_constant_expression_1 (t, true, tf_none); -} - -/* Like above, but complain about non-constant expressions. */ - -bool -require_potential_constant_expression (tree t) -{ - return potential_constant_expression_1 (t, false, tf_warning_or_error); -} - -/* Cross product of the above. */ - -bool -require_potential_rvalue_constant_expression (tree t) -{ - return potential_constant_expression_1 (t, true, tf_warning_or_error); -} - -/* Constructor for a lambda expression. */ - -tree -build_lambda_expr (void) -{ - tree lambda = make_node (LAMBDA_EXPR); - LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) = CPLD_NONE; - LAMBDA_EXPR_CAPTURE_LIST (lambda) = NULL_TREE; - LAMBDA_EXPR_THIS_CAPTURE (lambda) = NULL_TREE; - LAMBDA_EXPR_PENDING_PROXIES (lambda) = NULL; - LAMBDA_EXPR_RETURN_TYPE (lambda) = NULL_TREE; - LAMBDA_EXPR_MUTABLE_P (lambda) = false; - return lambda; -} - -/* Create the closure object for a LAMBDA_EXPR. */ - -tree -build_lambda_object (tree lambda_expr) -{ - /* Build aggregate constructor call. - - cp_parser_braced_list - - cp_parser_functional_cast */ - vec<constructor_elt, va_gc> *elts = NULL; - tree node, expr, type; - location_t saved_loc; - - if (processing_template_decl) - return lambda_expr; - - /* Make sure any error messages refer to the lambda-introducer. */ - saved_loc = input_location; - input_location = LAMBDA_EXPR_LOCATION (lambda_expr); - - for (node = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); - node; - node = TREE_CHAIN (node)) - { - tree field = TREE_PURPOSE (node); - tree val = TREE_VALUE (node); - - if (field == error_mark_node) - { - expr = error_mark_node; - goto out; - } - - if (DECL_P (val)) - mark_used (val); - - /* Mere mortals can't copy arrays with aggregate initialization, so - do some magic to make it work here. */ - if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE) - val = build_array_copy (val); - else if (DECL_NORMAL_CAPTURE_P (field) - && TREE_CODE (TREE_TYPE (field)) != REFERENCE_TYPE) - { - /* "the entities that are captured by copy are used to - direct-initialize each corresponding non-static data - member of the resulting closure object." - - There's normally no way to express direct-initialization - from an element of a CONSTRUCTOR, so we build up a special - TARGET_EXPR to bypass the usual copy-initialization. */ - val = force_rvalue (val, tf_warning_or_error); - if (TREE_CODE (val) == TARGET_EXPR) - TARGET_EXPR_DIRECT_INIT_P (val) = true; - } - - CONSTRUCTOR_APPEND_ELT (elts, DECL_NAME (field), val); - } - - expr = build_constructor (init_list_type_node, elts); - CONSTRUCTOR_IS_DIRECT_INIT (expr) = 1; - - /* N2927: "[The closure] class type is not an aggregate." - But we briefly treat it as an aggregate to make this simpler. */ - type = LAMBDA_EXPR_CLOSURE (lambda_expr); - CLASSTYPE_NON_AGGREGATE (type) = 0; - expr = finish_compound_literal (type, expr, tf_warning_or_error); - CLASSTYPE_NON_AGGREGATE (type) = 1; - - out: - input_location = saved_loc; - return expr; -} - -/* Return an initialized RECORD_TYPE for LAMBDA. - LAMBDA must have its explicit captures already. */ - -tree -begin_lambda_type (tree lambda) -{ - tree type; - - { - /* Unique name. This is just like an unnamed class, but we cannot use - make_anon_name because of certain checks against TYPE_ANONYMOUS_P. */ - tree name; - name = make_lambda_name (); - - /* Create the new RECORD_TYPE for this lambda. */ - type = xref_tag (/*tag_code=*/record_type, - name, - /*scope=*/ts_lambda, - /*template_header_p=*/false); - } - - /* Designate it as a struct so that we can use aggregate initialization. */ - CLASSTYPE_DECLARED_CLASS (type) = false; - - /* Cross-reference the expression and the type. */ - LAMBDA_EXPR_CLOSURE (lambda) = type; - CLASSTYPE_LAMBDA_EXPR (type) = lambda; - - /* Clear base types. */ - xref_basetypes (type, /*bases=*/NULL_TREE); - - /* Start the class. */ - type = begin_class_definition (type); - if (type == error_mark_node) - return error_mark_node; - - return type; -} - -/* Returns the type to use for the return type of the operator() of a - closure class. */ - -tree -lambda_return_type (tree expr) -{ - if (expr == NULL_TREE) - return void_type_node; - if (type_unknown_p (expr) - || BRACE_ENCLOSED_INITIALIZER_P (expr)) - { - cxx_incomplete_type_error (expr, TREE_TYPE (expr)); - return void_type_node; - } - gcc_checking_assert (!type_dependent_expression_p (expr)); - return cv_unqualified (type_decays_to (unlowered_expr_type (expr))); -} - -/* Given a LAMBDA_EXPR or closure type LAMBDA, return the op() of the - closure type. */ - -tree -lambda_function (tree lambda) -{ - tree type; - if (TREE_CODE (lambda) == LAMBDA_EXPR) - type = LAMBDA_EXPR_CLOSURE (lambda); - else - type = lambda; - gcc_assert (LAMBDA_TYPE_P (type)); - /* Don't let debug_tree cause instantiation. */ - if (CLASSTYPE_TEMPLATE_INSTANTIATION (type) - && !COMPLETE_OR_OPEN_TYPE_P (type)) - return NULL_TREE; - lambda = lookup_member (type, ansi_opname (CALL_EXPR), - /*protect=*/0, /*want_type=*/false, - tf_warning_or_error); - if (lambda) - lambda = BASELINK_FUNCTIONS (lambda); - return lambda; -} - -/* Returns the type to use for the FIELD_DECL corresponding to the - capture of EXPR. - The caller should add REFERENCE_TYPE for capture by reference. */ - -tree -lambda_capture_field_type (tree expr) -{ - tree type; - if (type_dependent_expression_p (expr) - && !(TREE_TYPE (expr) && TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)) - { - type = cxx_make_type (DECLTYPE_TYPE); - DECLTYPE_TYPE_EXPR (type) = expr; - DECLTYPE_FOR_LAMBDA_CAPTURE (type) = true; - SET_TYPE_STRUCTURAL_EQUALITY (type); - } - else - type = non_reference (unlowered_expr_type (expr)); - return type; -} - -/* Insert the deduced return type for an auto function. */ - -void -apply_deduced_return_type (tree fco, tree return_type) -{ - tree result; - - if (return_type == error_mark_node) - return; - - if (LAMBDA_FUNCTION_P (fco)) - { - tree lambda = CLASSTYPE_LAMBDA_EXPR (current_class_type); - LAMBDA_EXPR_RETURN_TYPE (lambda) = return_type; - } - - if (DECL_CONV_FN_P (fco)) - DECL_NAME (fco) = mangle_conv_op_name_for_type (return_type); - - TREE_TYPE (fco) = change_return_type (return_type, TREE_TYPE (fco)); - - result = DECL_RESULT (fco); - if (result == NULL_TREE) - return; - if (TREE_TYPE (result) == return_type) - return; - - /* We already have a DECL_RESULT from start_preparsed_function. - Now we need to redo the work it and allocate_struct_function - did to reflect the new type. */ - gcc_assert (current_function_decl == fco); - result = build_decl (input_location, RESULT_DECL, NULL_TREE, - TYPE_MAIN_VARIANT (return_type)); - DECL_ARTIFICIAL (result) = 1; - DECL_IGNORED_P (result) = 1; - cp_apply_type_quals_to_decl (cp_type_quals (return_type), - result); - - DECL_RESULT (fco) = result; - - if (!processing_template_decl) - { - bool aggr = aggregate_value_p (result, fco); -#ifdef PCC_STATIC_STRUCT_RETURN - cfun->returns_pcc_struct = aggr; -#endif - cfun->returns_struct = aggr; - } - -} - -/* DECL is a local variable or parameter from the surrounding scope of a - lambda-expression. Returns the decltype for a use of the capture field - for DECL even if it hasn't been captured yet. */ - -static tree -capture_decltype (tree decl) -{ - tree lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl)); - /* FIXME do lookup instead of list walk? */ - tree cap = value_member (decl, LAMBDA_EXPR_CAPTURE_LIST (lam)); - tree type; - - if (cap) - type = TREE_TYPE (TREE_PURPOSE (cap)); - else - switch (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam)) - { - case CPLD_NONE: - error ("%qD is not captured", decl); - return error_mark_node; - - case CPLD_COPY: - type = TREE_TYPE (decl); - if (TREE_CODE (type) == REFERENCE_TYPE - && TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE) - type = TREE_TYPE (type); - break; - - case CPLD_REFERENCE: - type = TREE_TYPE (decl); - if (TREE_CODE (type) != REFERENCE_TYPE) - type = build_reference_type (TREE_TYPE (decl)); - break; - - default: - gcc_unreachable (); - } - - if (TREE_CODE (type) != REFERENCE_TYPE) - { - if (!LAMBDA_EXPR_MUTABLE_P (lam)) - type = cp_build_qualified_type (type, (cp_type_quals (type) - |TYPE_QUAL_CONST)); - type = build_reference_type (type); - } - return type; -} - -/* Returns true iff DECL is a lambda capture proxy variable created by - build_capture_proxy. */ - -bool -is_capture_proxy (tree decl) -{ - return (TREE_CODE (decl) == VAR_DECL - && DECL_HAS_VALUE_EXPR_P (decl) - && !DECL_ANON_UNION_VAR_P (decl) - && LAMBDA_FUNCTION_P (DECL_CONTEXT (decl))); -} - -/* Returns true iff DECL is a capture proxy for a normal capture - (i.e. without explicit initializer). */ - -bool -is_normal_capture_proxy (tree decl) -{ - if (!is_capture_proxy (decl)) - /* It's not a capture proxy. */ - return false; - - /* It is a capture proxy, is it a normal capture? */ - tree val = DECL_VALUE_EXPR (decl); - if (val == error_mark_node) - return true; - - gcc_assert (TREE_CODE (val) == COMPONENT_REF); - val = TREE_OPERAND (val, 1); - return DECL_NORMAL_CAPTURE_P (val); -} - -/* VAR is a capture proxy created by build_capture_proxy; add it to the - current function, which is the operator() for the appropriate lambda. */ - -void -insert_capture_proxy (tree var) -{ - cp_binding_level *b; - tree stmt_list; - - /* Put the capture proxy in the extra body block so that it won't clash - with a later local variable. */ - b = current_binding_level; - for (;;) - { - cp_binding_level *n = b->level_chain; - if (n->kind == sk_function_parms) - break; - b = n; - } - pushdecl_with_scope (var, b, false); - - /* And put a DECL_EXPR in the STATEMENT_LIST for the same block. */ - var = build_stmt (DECL_SOURCE_LOCATION (var), DECL_EXPR, var); - stmt_list = (*stmt_list_stack)[1]; - gcc_assert (stmt_list); - append_to_statement_list_force (var, &stmt_list); -} - -/* We've just finished processing a lambda; if the containing scope is also - a lambda, insert any capture proxies that were created while processing - the nested lambda. */ - -void -insert_pending_capture_proxies (void) -{ - tree lam; - vec<tree, va_gc> *proxies; - unsigned i; - - if (!current_function_decl || !LAMBDA_FUNCTION_P (current_function_decl)) - return; - - lam = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (current_function_decl)); - proxies = LAMBDA_EXPR_PENDING_PROXIES (lam); - for (i = 0; i < vec_safe_length (proxies); ++i) - { - tree var = (*proxies)[i]; - insert_capture_proxy (var); - } - release_tree_vector (LAMBDA_EXPR_PENDING_PROXIES (lam)); - LAMBDA_EXPR_PENDING_PROXIES (lam) = NULL; -} - -/* Given REF, a COMPONENT_REF designating a field in the lambda closure, - return the type we want the proxy to have: the type of the field itself, - with added const-qualification if the lambda isn't mutable and the - capture is by value. */ - -tree -lambda_proxy_type (tree ref) -{ - tree type; - if (REFERENCE_REF_P (ref)) - ref = TREE_OPERAND (ref, 0); - type = TREE_TYPE (ref); - if (!dependent_type_p (type) - || (type && TREE_CODE (type) == POINTER_TYPE)) - return type; - type = cxx_make_type (DECLTYPE_TYPE); - DECLTYPE_TYPE_EXPR (type) = ref; - DECLTYPE_FOR_LAMBDA_PROXY (type) = true; - SET_TYPE_STRUCTURAL_EQUALITY (type); - return type; -} - -/* MEMBER is a capture field in a lambda closure class. Now that we're - inside the operator(), build a placeholder var for future lookups and - debugging. */ - -tree -build_capture_proxy (tree member) -{ - tree var, object, fn, closure, name, lam, type; - - closure = DECL_CONTEXT (member); - fn = lambda_function (closure); - lam = CLASSTYPE_LAMBDA_EXPR (closure); - - /* The proxy variable forwards to the capture field. */ - object = build_fold_indirect_ref (DECL_ARGUMENTS (fn)); - object = finish_non_static_data_member (member, object, NULL_TREE); - if (REFERENCE_REF_P (object)) - object = TREE_OPERAND (object, 0); - - /* Remove the __ inserted by add_capture. */ - name = get_identifier (IDENTIFIER_POINTER (DECL_NAME (member)) + 2); - - type = lambda_proxy_type (object); - var = build_decl (input_location, VAR_DECL, name, type); - SET_DECL_VALUE_EXPR (var, object); - DECL_HAS_VALUE_EXPR_P (var) = 1; - DECL_ARTIFICIAL (var) = 1; - TREE_USED (var) = 1; - DECL_CONTEXT (var) = fn; - - if (name == this_identifier) - { - gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (lam) == member); - LAMBDA_EXPR_THIS_CAPTURE (lam) = var; - } - - if (fn == current_function_decl) - insert_capture_proxy (var); - else - vec_safe_push (LAMBDA_EXPR_PENDING_PROXIES (lam), var); - - return var; -} - -/* From an ID and INITIALIZER, create a capture (by reference if - BY_REFERENCE_P is true), add it to the capture-list for LAMBDA, - and return it. */ - -tree -add_capture (tree lambda, tree id, tree initializer, bool by_reference_p, - bool explicit_init_p) -{ - char *buf; - tree type, member, name; - - type = lambda_capture_field_type (initializer); - if (by_reference_p) - { - type = build_reference_type (type); - if (!real_lvalue_p (initializer)) - error ("cannot capture %qE by reference", initializer); - } - else - /* Capture by copy requires a complete type. */ - type = complete_type (type); - - /* Add __ to the beginning of the field name so that user code - won't find the field with name lookup. We can't just leave the name - unset because template instantiation uses the name to find - instantiated fields. */ - buf = (char *) alloca (IDENTIFIER_LENGTH (id) + 3); - buf[1] = buf[0] = '_'; - memcpy (buf + 2, IDENTIFIER_POINTER (id), - IDENTIFIER_LENGTH (id) + 1); - name = get_identifier (buf); - - /* If TREE_TYPE isn't set, we're still in the introducer, so check - for duplicates. */ - if (!LAMBDA_EXPR_CLOSURE (lambda)) - { - if (IDENTIFIER_MARKED (name)) - { - pedwarn (input_location, 0, - "already captured %qD in lambda expression", id); - return NULL_TREE; - } - IDENTIFIER_MARKED (name) = true; - } - - /* Make member variable. */ - member = build_lang_decl (FIELD_DECL, name, type); - - if (!explicit_init_p) - /* Normal captures are invisible to name lookup but uses are replaced - with references to the capture field; we implement this by only - really making them invisible in unevaluated context; see - qualify_lookup. For now, let's make explicitly initialized captures - always visible. */ - DECL_NORMAL_CAPTURE_P (member) = true; - - if (id == this_identifier) - LAMBDA_EXPR_THIS_CAPTURE (lambda) = member; - - /* Add it to the appropriate closure class if we've started it. */ - if (current_class_type - && current_class_type == LAMBDA_EXPR_CLOSURE (lambda)) - finish_member_declaration (member); - - LAMBDA_EXPR_CAPTURE_LIST (lambda) - = tree_cons (member, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda)); - - if (LAMBDA_EXPR_CLOSURE (lambda)) - return build_capture_proxy (member); - /* For explicit captures we haven't started the function yet, so we wait - and build the proxy from cp_parser_lambda_body. */ - return NULL_TREE; -} - -/* Register all the capture members on the list CAPTURES, which is the - LAMBDA_EXPR_CAPTURE_LIST for the lambda after the introducer. */ - -void -register_capture_members (tree captures) -{ - if (captures == NULL_TREE) - return; - - register_capture_members (TREE_CHAIN (captures)); - /* We set this in add_capture to avoid duplicates. */ - IDENTIFIER_MARKED (DECL_NAME (TREE_PURPOSE (captures))) = false; - finish_member_declaration (TREE_PURPOSE (captures)); -} - -/* Similar to add_capture, except this works on a stack of nested lambdas. - BY_REFERENCE_P in this case is derived from the default capture mode. - Returns the capture for the lambda at the bottom of the stack. */ - -tree -add_default_capture (tree lambda_stack, tree id, tree initializer) -{ - bool this_capture_p = (id == this_identifier); - - tree var = NULL_TREE; - - tree saved_class_type = current_class_type; - - tree node; - - for (node = lambda_stack; - node; - node = TREE_CHAIN (node)) - { - tree lambda = TREE_VALUE (node); - - current_class_type = LAMBDA_EXPR_CLOSURE (lambda); - var = add_capture (lambda, - id, - initializer, - /*by_reference_p=*/ - (!this_capture_p - && (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) - == CPLD_REFERENCE)), - /*explicit_init_p=*/false); - initializer = convert_from_reference (var); - } - - current_class_type = saved_class_type; - - return var; -} - -/* Return the capture pertaining to a use of 'this' in LAMBDA, in the form of an - INDIRECT_REF, possibly adding it through default capturing. */ - -tree -lambda_expr_this_capture (tree lambda) -{ - tree result; - - tree this_capture = LAMBDA_EXPR_THIS_CAPTURE (lambda); - - /* In unevaluated context this isn't an odr-use, so just return the - nearest 'this'. */ - if (cp_unevaluated_operand) - return lookup_name (this_identifier); - - /* Try to default capture 'this' if we can. */ - if (!this_capture - && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda) != CPLD_NONE) - { - tree lambda_stack = NULL_TREE; - tree init = NULL_TREE; - - /* If we are in a lambda function, we can move out until we hit: - 1. a non-lambda function or NSDMI, - 2. a lambda function capturing 'this', or - 3. a non-default capturing lambda function. */ - for (tree tlambda = lambda; ;) - { - lambda_stack = tree_cons (NULL_TREE, - tlambda, - lambda_stack); - - if (LAMBDA_EXPR_EXTRA_SCOPE (tlambda) - && TREE_CODE (LAMBDA_EXPR_EXTRA_SCOPE (tlambda)) == FIELD_DECL) - { - /* In an NSDMI, we don't have a function to look up the decl in, - but the fake 'this' pointer that we're using for parsing is - in scope_chain. */ - init = scope_chain->x_current_class_ptr; - gcc_checking_assert - (init && (TREE_TYPE (TREE_TYPE (init)) - == current_nonlambda_class_type ())); - break; - } - - tree closure_decl = TYPE_NAME (LAMBDA_EXPR_CLOSURE (tlambda)); - tree containing_function = decl_function_context (closure_decl); - - if (containing_function == NULL_TREE) - /* We ran out of scopes; there's no 'this' to capture. */ - break; - - if (!LAMBDA_FUNCTION_P (containing_function)) - { - /* We found a non-lambda function. */ - if (DECL_NONSTATIC_MEMBER_FUNCTION_P (containing_function)) - /* First parameter is 'this'. */ - init = DECL_ARGUMENTS (containing_function); - break; - } - - tlambda - = CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (containing_function)); - - if (LAMBDA_EXPR_THIS_CAPTURE (tlambda)) - { - /* An outer lambda has already captured 'this'. */ - init = LAMBDA_EXPR_THIS_CAPTURE (tlambda); - break; - } - - if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (tlambda) == CPLD_NONE) - /* An outer lambda won't let us capture 'this'. */ - break; - } - - if (init) - this_capture = add_default_capture (lambda_stack, - /*id=*/this_identifier, - init); - } - - if (!this_capture) - { - error ("%<this%> was not captured for this lambda function"); - result = error_mark_node; - } - else - { - /* To make sure that current_class_ref is for the lambda. */ - gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (current_class_ref)) - == LAMBDA_EXPR_CLOSURE (lambda)); - - result = this_capture; - - /* If 'this' is captured, each use of 'this' is transformed into an - access to the corresponding unnamed data member of the closure - type cast (_expr.cast_ 5.4) to the type of 'this'. [ The cast - ensures that the transformed expression is an rvalue. ] */ - result = rvalue (result); - } - - return result; -} - -/* We don't want to capture 'this' until we know we need it, i.e. after - overload resolution has chosen a non-static member function. At that - point we call this function to turn a dummy object into a use of the - 'this' capture. */ - -tree -maybe_resolve_dummy (tree object) -{ - if (!is_dummy_object (object)) - return object; - - tree type = TYPE_MAIN_VARIANT (TREE_TYPE (object)); - gcc_assert (TREE_CODE (type) != POINTER_TYPE); - - if (type != current_class_type - && current_class_type - && LAMBDA_TYPE_P (current_class_type) - && DERIVED_FROM_P (type, current_nonlambda_class_type ())) - { - /* In a lambda, need to go through 'this' capture. */ - tree lam = CLASSTYPE_LAMBDA_EXPR (current_class_type); - tree cap = lambda_expr_this_capture (lam); - object = build_x_indirect_ref (EXPR_LOCATION (object), cap, - RO_NULL, tf_warning_or_error); - } - - return object; -} - -/* Returns the method basetype of the innermost non-lambda function, or - NULL_TREE if none. */ - -tree -nonlambda_method_basetype (void) -{ - tree fn, type; - if (!current_class_ref) - return NULL_TREE; - - type = current_class_type; - if (!LAMBDA_TYPE_P (type)) - return type; - - /* Find the nearest enclosing non-lambda function. */ - fn = TYPE_NAME (type); - do - fn = decl_function_context (fn); - while (fn && LAMBDA_FUNCTION_P (fn)); - - if (!fn || !DECL_NONSTATIC_MEMBER_FUNCTION_P (fn)) - return NULL_TREE; - - return TYPE_METHOD_BASETYPE (TREE_TYPE (fn)); -} - -/* If the closure TYPE has a static op(), also add a conversion to function - pointer. */ - -void -maybe_add_lambda_conv_op (tree type) -{ - bool nested = (current_function_decl != NULL_TREE); - tree callop = lambda_function (type); - tree rettype, name, fntype, fn, body, compound_stmt; - tree thistype, stattype, statfn, convfn, call, arg; - vec<tree, va_gc> *argvec; - - if (LAMBDA_EXPR_CAPTURE_LIST (CLASSTYPE_LAMBDA_EXPR (type)) != NULL_TREE) - return; - - if (processing_template_decl) - return; - - stattype = build_function_type (TREE_TYPE (TREE_TYPE (callop)), - FUNCTION_ARG_CHAIN (callop)); - - /* First build up the conversion op. */ - - rettype = build_pointer_type (stattype); - name = mangle_conv_op_name_for_type (rettype); - thistype = cp_build_qualified_type (type, TYPE_QUAL_CONST); - fntype = build_method_type_directly (thistype, rettype, void_list_node); - fn = convfn = build_lang_decl (FUNCTION_DECL, name, fntype); - DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); - - if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn - && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT) - DECL_ALIGN (fn) = 2 * BITS_PER_UNIT; - - SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR); - grokclassfn (type, fn, NO_SPECIAL); - set_linkage_according_to_type (type, fn); - rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof); - DECL_IN_AGGR_P (fn) = 1; - DECL_ARTIFICIAL (fn) = 1; - DECL_NOT_REALLY_EXTERN (fn) = 1; - DECL_DECLARED_INLINE_P (fn) = 1; - DECL_ARGUMENTS (fn) = build_this_parm (fntype, TYPE_QUAL_CONST); - if (nested) - DECL_INTERFACE_KNOWN (fn) = 1; - - add_method (type, fn, NULL_TREE); - - /* Generic thunk code fails for varargs; we'll complain in mark_used if - the conversion op is used. */ - if (varargs_function_p (callop)) - { - DECL_DELETED_FN (fn) = 1; - return; - } - - /* Now build up the thunk to be returned. */ - - name = get_identifier ("_FUN"); - fn = statfn = build_lang_decl (FUNCTION_DECL, name, stattype); - DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); - if (TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn - && DECL_ALIGN (fn) < 2 * BITS_PER_UNIT) - DECL_ALIGN (fn) = 2 * BITS_PER_UNIT; - grokclassfn (type, fn, NO_SPECIAL); - set_linkage_according_to_type (type, fn); - rest_of_decl_compilation (fn, toplevel_bindings_p (), at_eof); - DECL_IN_AGGR_P (fn) = 1; - DECL_ARTIFICIAL (fn) = 1; - DECL_NOT_REALLY_EXTERN (fn) = 1; - DECL_DECLARED_INLINE_P (fn) = 1; - DECL_STATIC_FUNCTION_P (fn) = 1; - DECL_ARGUMENTS (fn) = copy_list (DECL_CHAIN (DECL_ARGUMENTS (callop))); - for (arg = DECL_ARGUMENTS (fn); arg; arg = DECL_CHAIN (arg)) - DECL_CONTEXT (arg) = fn; - if (nested) - DECL_INTERFACE_KNOWN (fn) = 1; - - add_method (type, fn, NULL_TREE); - - if (nested) - push_function_context (); - else - /* Still increment function_depth so that we don't GC in the - middle of an expression. */ - ++function_depth; - - /* Generate the body of the thunk. */ - - start_preparsed_function (statfn, NULL_TREE, - SF_PRE_PARSED | SF_INCLASS_INLINE); - if (DECL_ONE_ONLY (statfn)) - { - /* Put the thunk in the same comdat group as the call op. */ - symtab_add_to_same_comdat_group - ((symtab_node) cgraph_get_create_node (statfn), - (symtab_node) cgraph_get_create_node (callop)); - } - body = begin_function_body (); - compound_stmt = begin_compound_stmt (0); - - arg = build1 (NOP_EXPR, TREE_TYPE (DECL_ARGUMENTS (callop)), - null_pointer_node); - argvec = make_tree_vector (); - argvec->quick_push (arg); - for (arg = DECL_ARGUMENTS (statfn); arg; arg = DECL_CHAIN (arg)) - { - mark_exp_read (arg); - vec_safe_push (argvec, arg); - } - call = build_call_a (callop, argvec->length (), argvec->address ()); - CALL_FROM_THUNK_P (call) = 1; - if (MAYBE_CLASS_TYPE_P (TREE_TYPE (call))) - call = build_cplus_new (TREE_TYPE (call), call, tf_warning_or_error); - call = convert_from_reference (call); - finish_return_stmt (call); - - finish_compound_stmt (compound_stmt); - finish_function_body (body); - - expand_or_defer_fn (finish_function (2)); - - /* Generate the body of the conversion op. */ - - start_preparsed_function (convfn, NULL_TREE, - SF_PRE_PARSED | SF_INCLASS_INLINE); - body = begin_function_body (); - compound_stmt = begin_compound_stmt (0); - - /* decl_needed_p needs to see that it's used. */ - TREE_USED (statfn) = 1; - finish_return_stmt (decay_conversion (statfn, tf_warning_or_error)); - - finish_compound_stmt (compound_stmt); - finish_function_body (body); - - expand_or_defer_fn (finish_function (2)); - - if (nested) - pop_function_context (); - else - --function_depth; -} - -/* Returns true iff VAL is a lambda-related declaration which should - be ignored by unqualified lookup. */ - -bool -is_lambda_ignored_entity (tree val) -{ - /* In unevaluated context, look past normal capture proxies. */ - if (cp_unevaluated_operand && is_normal_capture_proxy (val)) - return true; - - /* Always ignore lambda fields, their names are only for debugging. */ - if (TREE_CODE (val) == FIELD_DECL - && CLASSTYPE_LAMBDA_EXPR (DECL_CONTEXT (val))) - return true; - - /* None of the lookups that use qualify_lookup want the op() from the - lambda; they want the one from the enclosing class. */ - if (TREE_CODE (val) == FUNCTION_DECL && LAMBDA_FUNCTION_P (val)) - return true; - - return false; -} - -#include "gt-cp-semantics.h" |