aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/cp/semantics.c
diff options
context:
space:
mode:
authorBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
committerBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
commit1bc5aee63eb72b341f506ad058502cd0361f0d10 (patch)
treec607e8252f3405424ff15bc2d00aa38dadbb2518 /gcc-4.9/gcc/cp/semantics.c
parent283a0bf58fcf333c58a2a92c3ebbc41fb9eb1fdb (diff)
downloadtoolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.gz
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.bz2
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.zip
Initial checkin of GCC 4.9.0 from trunk (r208799).
Change-Id: I48a3c08bb98542aa215912a75f03c0890e497dba
Diffstat (limited to 'gcc-4.9/gcc/cp/semantics.c')
-rw-r--r--gcc-4.9/gcc/cp/semantics.c10691
1 files changed, 10691 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/cp/semantics.c b/gcc-4.9/gcc/cp/semantics.c
new file mode 100644
index 000000000..886fbb88b
--- /dev/null
+++ b/gcc-4.9/gcc/cp/semantics.c
@@ -0,0 +1,10691 @@
+/* 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-2014 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 "stmt.h"
+#include "varasm.h"
+#include "stor-layout.h"
+#include "stringpool.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 "target.h"
+#include "pointer-set.h"
+#include "hash-table.h"
+#include "gimplify.h"
+#include "bitmap.h"
+#include "omp-low.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);
+ }
+}
+
+/* Save the current deferred access states and start deferred access
+ checking, continuing the set of deferred checks in CHECKS. */
+
+void
+reopen_deferring_access_checks (vec<deferred_access_check, va_gc> * checks)
+{
+ push_deferring_access_checks (dk_deferred);
+ if (!deferred_access_no_check)
+ deferred_access_stack->last().deferred_access_checks = checks;
+}
+
+/* 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 ();
+}
+
+/* Simple infinite loop tracking for -Wreturn-type. We keep a stack of all
+ the current loops, represented by 'NULL_TREE' if we've seen a possible
+ exit, and 'error_mark_node' if not. This is currently used only to
+ suppress the warning about a function with no return statements, and
+ therefore we don't bother noting returns as possible exits. We also
+ don't bother with gotos. */
+
+static void
+begin_maybe_infinite_loop (tree cond)
+{
+ /* Only track this while parsing a function, not during instantiation. */
+ if (!cfun || (DECL_TEMPLATE_INSTANTIATION (current_function_decl)
+ && !processing_template_decl))
+ return;
+ bool maybe_infinite = true;
+ if (cond)
+ {
+ cond = fold_non_dependent_expr_sfinae (cond, tf_none);
+ cond = maybe_constant_value (cond);
+ maybe_infinite = integer_nonzerop (cond);
+ }
+ vec_safe_push (cp_function_chain->infinite_loops,
+ maybe_infinite ? error_mark_node : NULL_TREE);
+
+}
+
+/* A break is a possible exit for the current loop. */
+
+void
+break_maybe_infinite_loop (void)
+{
+ if (!cfun)
+ return;
+ cp_function_chain->infinite_loops->last() = NULL_TREE;
+}
+
+/* If we reach the end of the loop without seeing a possible exit, we have
+ an infinite loop. */
+
+static void
+end_maybe_infinite_loop (tree cond)
+{
+ if (!cfun || (DECL_TEMPLATE_INSTANTIATION (current_function_decl)
+ && !processing_template_decl))
+ return;
+ tree current = cp_function_chain->infinite_loops->pop();
+ if (current != NULL_TREE)
+ {
+ cond = fold_non_dependent_expr (cond);
+ cond = maybe_constant_value (cond);
+ if (integer_nonzerop (cond))
+ current_function_infinite_loop = 1;
+ }
+}
+
+
+/* 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 (identifier_p (destination))
+ 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);
+ }
+
+ 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));
+}
+
+/* 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, bool ivdep)
+{
+ cond = maybe_convert_cond (cond);
+ finish_cond (&WHILE_COND (while_stmt), cond);
+ begin_maybe_infinite_loop (cond);
+ if (ivdep && cond != error_mark_node)
+ WHILE_COND (while_stmt) = build2 (ANNOTATE_EXPR,
+ TREE_TYPE (WHILE_COND (while_stmt)),
+ WHILE_COND (while_stmt),
+ build_int_cst (integer_type_node,
+ annot_expr_ivdep_kind));
+ 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)
+{
+ end_maybe_infinite_loop (boolean_true_node);
+ WHILE_BODY (while_stmt) = do_poplevel (WHILE_BODY (while_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);
+ begin_maybe_infinite_loop (boolean_true_node);
+ 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, bool ivdep)
+{
+ cond = maybe_convert_cond (cond);
+ end_maybe_infinite_loop (cond);
+ if (ivdep && cond != error_mark_node)
+ cond = build2 (ANNOTATE_EXPR, TREE_TYPE (cond), cond,
+ build_int_cst (integer_type_node, annot_expr_ivdep_kind));
+ DO_COND (do_stmt) = cond;
+}
+
+/* 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 (error_operand_p (expr)
+ || (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);
+
+ 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, bool ivdep)
+{
+ cond = maybe_convert_cond (cond);
+ finish_cond (&FOR_COND (for_stmt), cond);
+ begin_maybe_infinite_loop (cond);
+ if (ivdep && cond != error_mark_node)
+ FOR_COND (for_stmt) = build2 (ANNOTATE_EXPR,
+ TREE_TYPE (FOR_COND (for_stmt)),
+ FOR_COND (for_stmt),
+ build_int_cst (integer_type_node,
+ annot_expr_ivdep_kind));
+ 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)
+{
+ end_maybe_infinite_loop (boolean_true_node);
+
+ 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));
+ }
+}
+
+/* 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;
+
+ begin_maybe_infinite_loop (boolean_false_node);
+
+ 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 ();
+
+ 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;
+}
+
+/* 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 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);
+}
+
+/* Obfuscate EXPR if it looks like an id-expression or member access so
+ that the call to finish_decltype in do_auto_deduction will give the
+ right result. */
+
+tree
+force_paren_expr (tree expr)
+{
+ /* This is only needed for decltype(auto) in C++14. */
+ if (cxx_dialect < cxx1y)
+ return expr;
+
+ /* If we're in unevaluated context, we can't be deducing a
+ return/initializer type, so we don't need to mess with this. */
+ if (cp_unevaluated_operand)
+ return expr;
+
+ if (!DECL_P (expr) && TREE_CODE (expr) != COMPONENT_REF
+ && TREE_CODE (expr) != SCOPE_REF)
+ return expr;
+
+ if (TREE_CODE (expr) == COMPONENT_REF)
+ REF_PARENTHESIZED_P (expr) = true;
+ else if (type_dependent_expression_p (expr))
+ expr = build1 (PAREN_EXPR, TREE_TYPE (expr), expr);
+ else
+ {
+ cp_lvalue_kind kind = lvalue_kind (expr);
+ if ((kind & ~clk_class) != clk_none)
+ {
+ tree type = unlowered_expr_type (expr);
+ bool rval = !!(kind & clk_rvalueref);
+ type = cp_build_reference_type (type, rval);
+ expr = build_static_cast (type, expr, tf_error);
+ }
+ }
+
+ return expr;
+}
+
+/* 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;
+
+ expr = force_paren_expr (expr);
+
+ return expr;
+}
+
+/* Finish a reference to a non-static data member (DECL) that is not
+ preceded by `.' or `->'. */
+
+tree
+finish_non_static_data_member (tree decl, tree object, tree qualifying_scope)
+{
+ 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 if (PACK_EXPANSION_P (type))
+ /* Don't bother trying to represent this. */
+ type = NULL_TREE;
+ 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, complain))
+ return error_mark_node;
+
+ 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. Returns the functions to be considered by overload resolution. */
+
+tree
+perform_koenig_lookup (tree fn, vec<tree, va_gc> *args,
+ 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 (identifier_p (fn))
+ 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);
+ 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_LOC (fn, input_location));
+ 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);
+ }
+ }
+
+ /* Per 13.3.1.1, '(&f)(...)' is the same as '(f)(...)'. */
+ if (TREE_CODE (fn) == ADDR_EXPR
+ && TREE_CODE (TREE_OPERAND (fn, 0)) == OVERLOAD)
+ fn = TREE_OPERAND (fn, 0);
+
+ 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 (INDIRECT_REF_P (result))
+ 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;
+ }
+
+ /* The keyword 'this' is a prvalue expression. */
+ result = rvalue (result);
+
+ 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,
+ location_t loc)
+{
+ 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_at (loc, "invalid qualifying scope in pseudo-destructor name");
+ return error_mark_node;
+ }
+ if (is_auto (destructor))
+ destructor = TREE_TYPE (object);
+ if (scope && TYPE_P (scope) && !check_dtor_name (scope, destructor))
+ {
+ error_at (loc,
+ "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_at (loc, "%qE is not of type %qT", object, destructor);
+ return error_mark_node;
+ }
+ }
+
+ return build3_loc (loc, 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)
+ && !cp_unevaluated_operand
+ && 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));
+ /* Make sure the destructor is callable. */
+ tree clean = cxx_maybe_build_cleanup (decl, complain);
+ if (clean == error_mark_node)
+ return error_mark_node;
+ 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 != error_mark_node)
+ 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 (LOCATION_FILE (input_location));
+ 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 (DECL_DECLARES_FUNCTION_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, if the class
+ isn't a closure (whose fields are supposed to be unnamed). */
+ else if (CLASSTYPE_LAMBDA_EXPR (current_class_type)
+ || 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 (VAR_OR_FUNCTION_DECL_P (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 ((VAR_P (decl) || TREE_CODE (decl) == PARM_DECL)
+ && DECL_FUNCTION_SCOPE_P (decl)
+ && (DECL_CONTEXT (decl) != current_function_decl
+ || parsing_nsdmi ()));
+}
+
+/* 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)
+ && !(identifier_p (id_expression)
+ && 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 && identifier_p (id_expression))
+ 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))
+ /* OK */;
+ else if (TREE_STATIC (decl)
+ /* It's not a use (3.2) if we're in an unevaluated context. */
+ || cp_unevaluated_operand)
+ {
+ if (processing_template_decl)
+ /* For a use of an outer static/unevaluated var, return the id
+ 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 (parsing_nsdmi ())
+ containing_function = NULL_TREE;
+ /* 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. */
+ else 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 (lambda_expr && TREE_CODE (decl) == VAR_DECL
+ && DECL_ANON_UNION_VAR_P (decl))
+ {
+ error ("cannot capture member %qD of anonymous union", decl);
+ return error_mark_node;
+ }
+ 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 (VAR_P (decl)
+ ? G_("use of local variable with automatic storage from containing function")
+ : G_("use of parameter from containing function"));
+ inform (input_location, "%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_msg = "use of parameter outside function body";
+ 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
+ && (identifier_p (TREE_OPERAND (decl, 0))))
+ 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 (VAR_P (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 ((VAR_P (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 (VAR_P (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);
+ }
+ }
+
+ /* Handle references (c++/56130). */
+ tree t = REFERENCE_REF_P (decl) ? TREE_OPERAND (decl, 0) : decl;
+ if (TREE_DEPRECATED (t))
+ warn_deprecated_use (t, 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 (INDIRECT_REF_P (expr))
+ error ("second operand of %<offsetof%> is neither a single "
+ "identifier nor a sequence of member accesses and "
+ "array references");
+ else
+ {
+ 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_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));
+
+ /* 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)
+ tentative_decl_linkage (fn);
+ 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;
+ }
+ }
+
+ /* 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;
+ }
+
+ /* 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,
+ bool need_dtor)
+{
+ 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_dtor && 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;
+}
+
+/* Helper function for handle_omp_array_sections. Called recursively
+ to handle multiple array-section-subscripts. C is the clause,
+ T current expression (initially OMP_CLAUSE_DECL), which is either
+ a TREE_LIST for array-section-subscript (TREE_PURPOSE is low-bound
+ expression if specified, TREE_VALUE length expression if specified,
+ TREE_CHAIN is what it has been specified after, or some decl.
+ TYPES vector is populated with array section types, MAYBE_ZERO_LEN
+ set to true if any of the array-section-subscript could have length
+ of zero (explicit or implicit), FIRST_NON_ONE is the index of the
+ first array-section-subscript which is known not to have length
+ of one. Given say:
+ map(a[:b][2:1][:c][:2][:d][e:f][2:5])
+ FIRST_NON_ONE will be 3, array-section-subscript [:b], [2:1] and [:c]
+ all are or may have length of 1, array-section-subscript [:2] is the
+ first one knonwn not to have length 1. For array-section-subscript
+ <= FIRST_NON_ONE we diagnose non-contiguous arrays if low bound isn't
+ 0 or length isn't the array domain max + 1, for > FIRST_NON_ONE we
+ can if MAYBE_ZERO_LEN is false. MAYBE_ZERO_LEN will be true in the above
+ case though, as some lengths could be zero. */
+
+static tree
+handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
+ bool &maybe_zero_len, unsigned int &first_non_one)
+{
+ tree ret, low_bound, length, type;
+ if (TREE_CODE (t) != TREE_LIST)
+ {
+ if (error_operand_p (t))
+ return error_mark_node;
+ if (type_dependent_expression_p (t))
+ return NULL_TREE;
+ if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ {
+ if (processing_template_decl)
+ return NULL_TREE;
+ if (DECL_P (t))
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD is not a variable in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ else
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE is not a variable in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
+ && TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD is threadprivate variable in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ t = convert_from_reference (t);
+ return t;
+ }
+
+ ret = handle_omp_array_sections_1 (c, TREE_CHAIN (t), types,
+ maybe_zero_len, first_non_one);
+ if (ret == error_mark_node || ret == NULL_TREE)
+ return ret;
+
+ type = TREE_TYPE (ret);
+ low_bound = TREE_PURPOSE (t);
+ length = TREE_VALUE (t);
+ if ((low_bound && type_dependent_expression_p (low_bound))
+ || (length && type_dependent_expression_p (length)))
+ return NULL_TREE;
+
+ if (low_bound == error_mark_node || length == error_mark_node)
+ return error_mark_node;
+
+ if (low_bound && !INTEGRAL_TYPE_P (TREE_TYPE (low_bound)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "low bound %qE of array section does not have integral type",
+ low_bound);
+ return error_mark_node;
+ }
+ if (length && !INTEGRAL_TYPE_P (TREE_TYPE (length)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "length %qE of array section does not have integral type",
+ length);
+ return error_mark_node;
+ }
+ if (low_bound
+ && TREE_CODE (low_bound) == INTEGER_CST
+ && TYPE_PRECISION (TREE_TYPE (low_bound))
+ > TYPE_PRECISION (sizetype))
+ low_bound = fold_convert (sizetype, low_bound);
+ if (length
+ && TREE_CODE (length) == INTEGER_CST
+ && TYPE_PRECISION (TREE_TYPE (length))
+ > TYPE_PRECISION (sizetype))
+ length = fold_convert (sizetype, length);
+ if (low_bound == NULL_TREE)
+ low_bound = integer_zero_node;
+
+ if (length != NULL_TREE)
+ {
+ if (!integer_nonzerop (length))
+ maybe_zero_len = true;
+ if (first_non_one == types.length ()
+ && (TREE_CODE (length) != INTEGER_CST || integer_onep (length)))
+ first_non_one++;
+ }
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ if (length == NULL_TREE
+ && (TYPE_DOMAIN (type) == NULL_TREE
+ || TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "for unknown bound array type length expression must "
+ "be specified");
+ return error_mark_node;
+ }
+ if (TREE_CODE (low_bound) == INTEGER_CST
+ && tree_int_cst_sgn (low_bound) == -1)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "negative low bound in array section in %qs clause",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ if (length != NULL_TREE
+ && TREE_CODE (length) == INTEGER_CST
+ && tree_int_cst_sgn (length) == -1)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "negative length in array section in %qs clause",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ if (TYPE_DOMAIN (type)
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (type))
+ && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (type)))
+ == INTEGER_CST)
+ {
+ tree size = size_binop (PLUS_EXPR,
+ TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
+ size_one_node);
+ if (TREE_CODE (low_bound) == INTEGER_CST)
+ {
+ if (tree_int_cst_lt (size, low_bound))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "low bound %qE above array section size "
+ "in %qs clause", low_bound,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ if (tree_int_cst_equal (size, low_bound))
+ maybe_zero_len = true;
+ else if (length == NULL_TREE
+ && first_non_one == types.length ()
+ && tree_int_cst_equal
+ (TYPE_MAX_VALUE (TYPE_DOMAIN (type)),
+ low_bound))
+ first_non_one++;
+ }
+ else if (length == NULL_TREE)
+ {
+ maybe_zero_len = true;
+ if (first_non_one == types.length ())
+ first_non_one++;
+ }
+ if (length && TREE_CODE (length) == INTEGER_CST)
+ {
+ if (tree_int_cst_lt (size, length))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "length %qE above array section size "
+ "in %qs clause", length,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ if (TREE_CODE (low_bound) == INTEGER_CST)
+ {
+ tree lbpluslen
+ = size_binop (PLUS_EXPR,
+ fold_convert (sizetype, low_bound),
+ fold_convert (sizetype, length));
+ if (TREE_CODE (lbpluslen) == INTEGER_CST
+ && tree_int_cst_lt (size, lbpluslen))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "high bound %qE above array section size "
+ "in %qs clause", lbpluslen,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ }
+ }
+ }
+ else if (length == NULL_TREE)
+ {
+ maybe_zero_len = true;
+ if (first_non_one == types.length ())
+ first_non_one++;
+ }
+
+ /* For [lb:] we will need to evaluate lb more than once. */
+ if (length == NULL_TREE && OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
+ {
+ tree lb = cp_save_expr (low_bound);
+ if (lb != low_bound)
+ {
+ TREE_PURPOSE (t) = lb;
+ low_bound = lb;
+ }
+ }
+ }
+ else if (TREE_CODE (type) == POINTER_TYPE)
+ {
+ if (length == NULL_TREE)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "for pointer type length expression must be specified");
+ return error_mark_node;
+ }
+ /* If there is a pointer type anywhere but in the very first
+ array-section-subscript, the array section can't be contiguous. */
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND
+ && TREE_CODE (TREE_CHAIN (t)) == TREE_LIST)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "array section is not contiguous in %qs clause",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return error_mark_node;
+ }
+ }
+ else
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE does not have pointer or array type", ret);
+ return error_mark_node;
+ }
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_DEPEND)
+ types.safe_push (TREE_TYPE (ret));
+ /* We will need to evaluate lb more than once. */
+ tree lb = cp_save_expr (low_bound);
+ if (lb != low_bound)
+ {
+ TREE_PURPOSE (t) = lb;
+ low_bound = lb;
+ }
+ ret = grok_array_decl (OMP_CLAUSE_LOCATION (c), ret, low_bound, false);
+ return ret;
+}
+
+/* Handle array sections for clause C. */
+
+static bool
+handle_omp_array_sections (tree c)
+{
+ bool maybe_zero_len = false;
+ unsigned int first_non_one = 0;
+ auto_vec<tree> types;
+ tree first = handle_omp_array_sections_1 (c, OMP_CLAUSE_DECL (c), types,
+ maybe_zero_len, first_non_one);
+ if (first == error_mark_node)
+ return true;
+ if (first == NULL_TREE)
+ return false;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_DEPEND)
+ {
+ tree t = OMP_CLAUSE_DECL (c);
+ tree tem = NULL_TREE;
+ if (processing_template_decl)
+ return false;
+ /* Need to evaluate side effects in the length expressions
+ if any. */
+ while (TREE_CODE (t) == TREE_LIST)
+ {
+ if (TREE_VALUE (t) && TREE_SIDE_EFFECTS (TREE_VALUE (t)))
+ {
+ if (tem == NULL_TREE)
+ tem = TREE_VALUE (t);
+ else
+ tem = build2 (COMPOUND_EXPR, TREE_TYPE (tem),
+ TREE_VALUE (t), tem);
+ }
+ t = TREE_CHAIN (t);
+ }
+ if (tem)
+ first = build2 (COMPOUND_EXPR, TREE_TYPE (first), tem, first);
+ OMP_CLAUSE_DECL (c) = first;
+ }
+ else
+ {
+ unsigned int num = types.length (), i;
+ tree t, side_effects = NULL_TREE, size = NULL_TREE;
+ tree condition = NULL_TREE;
+
+ if (int_size_in_bytes (TREE_TYPE (first)) <= 0)
+ maybe_zero_len = true;
+ if (processing_template_decl && maybe_zero_len)
+ return false;
+
+ for (i = num, t = OMP_CLAUSE_DECL (c); i > 0;
+ t = TREE_CHAIN (t))
+ {
+ tree low_bound = TREE_PURPOSE (t);
+ tree length = TREE_VALUE (t);
+
+ i--;
+ if (low_bound
+ && TREE_CODE (low_bound) == INTEGER_CST
+ && TYPE_PRECISION (TREE_TYPE (low_bound))
+ > TYPE_PRECISION (sizetype))
+ low_bound = fold_convert (sizetype, low_bound);
+ if (length
+ && TREE_CODE (length) == INTEGER_CST
+ && TYPE_PRECISION (TREE_TYPE (length))
+ > TYPE_PRECISION (sizetype))
+ length = fold_convert (sizetype, length);
+ if (low_bound == NULL_TREE)
+ low_bound = integer_zero_node;
+ if (!maybe_zero_len && i > first_non_one)
+ {
+ if (integer_nonzerop (low_bound))
+ goto do_warn_noncontiguous;
+ if (length != NULL_TREE
+ && TREE_CODE (length) == INTEGER_CST
+ && TYPE_DOMAIN (types[i])
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (types[i]))
+ && TREE_CODE (TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])))
+ == INTEGER_CST)
+ {
+ tree size;
+ size = size_binop (PLUS_EXPR,
+ TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])),
+ size_one_node);
+ if (!tree_int_cst_equal (length, size))
+ {
+ do_warn_noncontiguous:
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "array section is not contiguous in %qs "
+ "clause",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ return true;
+ }
+ }
+ if (!processing_template_decl
+ && length != NULL_TREE
+ && TREE_SIDE_EFFECTS (length))
+ {
+ if (side_effects == NULL_TREE)
+ side_effects = length;
+ else
+ side_effects = build2 (COMPOUND_EXPR,
+ TREE_TYPE (side_effects),
+ length, side_effects);
+ }
+ }
+ else if (processing_template_decl)
+ continue;
+ else
+ {
+ tree l;
+
+ if (i > first_non_one && length && integer_nonzerop (length))
+ continue;
+ if (length)
+ l = fold_convert (sizetype, length);
+ else
+ {
+ l = size_binop (PLUS_EXPR,
+ TYPE_MAX_VALUE (TYPE_DOMAIN (types[i])),
+ size_one_node);
+ l = size_binop (MINUS_EXPR, l,
+ fold_convert (sizetype, low_bound));
+ }
+ if (i > first_non_one)
+ {
+ l = fold_build2 (NE_EXPR, boolean_type_node, l,
+ size_zero_node);
+ if (condition == NULL_TREE)
+ condition = l;
+ else
+ condition = fold_build2 (BIT_AND_EXPR, boolean_type_node,
+ l, condition);
+ }
+ else if (size == NULL_TREE)
+ {
+ size = size_in_bytes (TREE_TYPE (types[i]));
+ size = size_binop (MULT_EXPR, size, l);
+ if (condition)
+ size = fold_build3 (COND_EXPR, sizetype, condition,
+ size, size_zero_node);
+ }
+ else
+ size = size_binop (MULT_EXPR, size, l);
+ }
+ }
+ if (!processing_template_decl)
+ {
+ if (side_effects)
+ size = build2 (COMPOUND_EXPR, sizetype, side_effects, size);
+ OMP_CLAUSE_DECL (c) = first;
+ OMP_CLAUSE_SIZE (c) = size;
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+ return false;
+ tree c2 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+ OMP_CLAUSE_MAP);
+ OMP_CLAUSE_MAP_KIND (c2) = OMP_CLAUSE_MAP_POINTER;
+ if (!cxx_mark_addressable (t))
+ return false;
+ OMP_CLAUSE_DECL (c2) = t;
+ t = build_fold_addr_expr (first);
+ t = fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+ ptrdiff_type_node, t);
+ tree ptr = OMP_CLAUSE_DECL (c2);
+ ptr = convert_from_reference (ptr);
+ if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
+ ptr = build_fold_addr_expr (ptr);
+ t = fold_build2_loc (OMP_CLAUSE_LOCATION (c), MINUS_EXPR,
+ ptrdiff_type_node, t,
+ fold_convert_loc (OMP_CLAUSE_LOCATION (c),
+ ptrdiff_type_node, ptr));
+ OMP_CLAUSE_SIZE (c2) = t;
+ OMP_CLAUSE_CHAIN (c2) = OMP_CLAUSE_CHAIN (c);
+ OMP_CLAUSE_CHAIN (c) = c2;
+ ptr = OMP_CLAUSE_DECL (c2);
+ if (TREE_CODE (TREE_TYPE (ptr)) == REFERENCE_TYPE
+ && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (ptr))))
+ {
+ tree c3 = build_omp_clause (OMP_CLAUSE_LOCATION (c),
+ OMP_CLAUSE_MAP);
+ OMP_CLAUSE_MAP_KIND (c3) = OMP_CLAUSE_MAP_POINTER;
+ OMP_CLAUSE_DECL (c3) = ptr;
+ OMP_CLAUSE_DECL (c2) = convert_from_reference (ptr);
+ OMP_CLAUSE_SIZE (c3) = size_zero_node;
+ OMP_CLAUSE_CHAIN (c3) = OMP_CLAUSE_CHAIN (c2);
+ OMP_CLAUSE_CHAIN (c2) = c3;
+ }
+ }
+ }
+ return false;
+}
+
+/* Return identifier to look up for omp declare reduction. */
+
+tree
+omp_reduction_id (enum tree_code reduction_code, tree reduction_id, tree type)
+{
+ const char *p = NULL;
+ const char *m = NULL;
+ switch (reduction_code)
+ {
+ case PLUS_EXPR:
+ case MULT_EXPR:
+ case MINUS_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_XOR_EXPR:
+ case BIT_IOR_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ reduction_id = ansi_opname (reduction_code);
+ break;
+ case MIN_EXPR:
+ p = "min";
+ break;
+ case MAX_EXPR:
+ p = "max";
+ break;
+ default:
+ break;
+ }
+
+ if (p == NULL)
+ {
+ if (TREE_CODE (reduction_id) != IDENTIFIER_NODE)
+ return error_mark_node;
+ p = IDENTIFIER_POINTER (reduction_id);
+ }
+
+ if (type != NULL_TREE)
+ m = mangle_type_string (TYPE_MAIN_VARIANT (type));
+
+ const char prefix[] = "omp declare reduction ";
+ size_t lenp = sizeof (prefix);
+ if (strncmp (p, prefix, lenp - 1) == 0)
+ lenp = 1;
+ size_t len = strlen (p);
+ size_t lenm = m ? strlen (m) + 1 : 0;
+ char *name = XALLOCAVEC (char, lenp + len + lenm);
+ if (lenp > 1)
+ memcpy (name, prefix, lenp - 1);
+ memcpy (name + lenp - 1, p, len + 1);
+ if (m)
+ {
+ name[lenp + len - 1] = '~';
+ memcpy (name + lenp + len, m, lenm);
+ }
+ return get_identifier (name);
+}
+
+/* Lookup OpenMP UDR ID for TYPE, return the corresponding artificial
+ FUNCTION_DECL or NULL_TREE if not found. */
+
+static tree
+omp_reduction_lookup (location_t loc, tree id, tree type, tree *baselinkp,
+ vec<tree> *ambiguousp)
+{
+ tree orig_id = id;
+ tree baselink = NULL_TREE;
+ if (identifier_p (id))
+ {
+ cp_id_kind idk;
+ bool nonint_cst_expression_p;
+ const char *error_msg;
+ id = omp_reduction_id (ERROR_MARK, id, type);
+ tree decl = lookup_name (id);
+ if (decl == NULL_TREE)
+ decl = error_mark_node;
+ id = finish_id_expression (id, decl, NULL_TREE, &idk, false, true,
+ &nonint_cst_expression_p, false, true, false,
+ false, &error_msg, loc);
+ if (idk == CP_ID_KIND_UNQUALIFIED
+ && identifier_p (id))
+ {
+ vec<tree, va_gc> *args = NULL;
+ vec_safe_push (args, build_reference_type (type));
+ id = perform_koenig_lookup (id, args, tf_none);
+ }
+ }
+ else if (TREE_CODE (id) == SCOPE_REF)
+ id = lookup_qualified_name (TREE_OPERAND (id, 0),
+ omp_reduction_id (ERROR_MARK,
+ TREE_OPERAND (id, 1),
+ type),
+ false, false);
+ tree fns = id;
+ if (id && is_overloaded_fn (id))
+ id = get_fns (id);
+ for (; id; id = OVL_NEXT (id))
+ {
+ tree fndecl = OVL_CURRENT (id);
+ if (TREE_CODE (fndecl) == FUNCTION_DECL)
+ {
+ tree argtype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (fndecl)));
+ if (same_type_p (TREE_TYPE (argtype), type))
+ break;
+ }
+ }
+ if (id && BASELINK_P (fns))
+ {
+ if (baselinkp)
+ *baselinkp = fns;
+ else
+ baselink = fns;
+ }
+ if (id == NULL_TREE && CLASS_TYPE_P (type) && TYPE_BINFO (type))
+ {
+ vec<tree> ambiguous = vNULL;
+ tree binfo = TYPE_BINFO (type), base_binfo, ret = NULL_TREE;
+ unsigned int ix;
+ if (ambiguousp == NULL)
+ ambiguousp = &ambiguous;
+ for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
+ {
+ id = omp_reduction_lookup (loc, orig_id, BINFO_TYPE (base_binfo),
+ baselinkp ? baselinkp : &baselink,
+ ambiguousp);
+ if (id == NULL_TREE)
+ continue;
+ if (!ambiguousp->is_empty ())
+ ambiguousp->safe_push (id);
+ else if (ret != NULL_TREE)
+ {
+ ambiguousp->safe_push (ret);
+ ambiguousp->safe_push (id);
+ ret = NULL_TREE;
+ }
+ else
+ ret = id;
+ }
+ if (ambiguousp != &ambiguous)
+ return ret;
+ if (!ambiguous.is_empty ())
+ {
+ const char *str = _("candidates are:");
+ unsigned int idx;
+ tree udr;
+ error_at (loc, "user defined reduction lookup is ambiguous");
+ FOR_EACH_VEC_ELT (ambiguous, idx, udr)
+ {
+ inform (DECL_SOURCE_LOCATION (udr), "%s %#D", str, udr);
+ if (idx == 0)
+ str = get_spaces (str);
+ }
+ ambiguous.release ();
+ ret = error_mark_node;
+ baselink = NULL_TREE;
+ }
+ id = ret;
+ }
+ if (id && baselink)
+ perform_or_defer_access_check (BASELINK_BINFO (baselink),
+ id, id, tf_warning_or_error);
+ return id;
+}
+
+/* Helper function for cp_parser_omp_declare_reduction_exprs
+ and tsubst_omp_udr.
+ Remove CLEANUP_STMT for data (omp_priv variable).
+ Also append INIT_EXPR for DECL_INITIAL of omp_priv after its
+ DECL_EXPR. */
+
+tree
+cp_remove_omp_priv_cleanup_stmt (tree *tp, int *walk_subtrees, void *data)
+{
+ if (TYPE_P (*tp))
+ *walk_subtrees = 0;
+ else if (TREE_CODE (*tp) == CLEANUP_STMT && CLEANUP_DECL (*tp) == (tree) data)
+ *tp = CLEANUP_BODY (*tp);
+ else if (TREE_CODE (*tp) == DECL_EXPR)
+ {
+ tree decl = DECL_EXPR_DECL (*tp);
+ if (!processing_template_decl
+ && decl == (tree) data
+ && DECL_INITIAL (decl)
+ && DECL_INITIAL (decl) != error_mark_node)
+ {
+ tree list = NULL_TREE;
+ append_to_statement_list_force (*tp, &list);
+ tree init_expr = build2 (INIT_EXPR, void_type_node,
+ decl, DECL_INITIAL (decl));
+ DECL_INITIAL (decl) = NULL_TREE;
+ append_to_statement_list_force (init_expr, &list);
+ *tp = list;
+ }
+ }
+ return NULL_TREE;
+}
+
+/* Data passed from cp_check_omp_declare_reduction to
+ cp_check_omp_declare_reduction_r. */
+
+struct cp_check_omp_declare_reduction_data
+{
+ location_t loc;
+ tree stmts[7];
+ bool combiner_p;
+};
+
+/* Helper function for cp_check_omp_declare_reduction, called via
+ cp_walk_tree. */
+
+static tree
+cp_check_omp_declare_reduction_r (tree *tp, int *, void *data)
+{
+ struct cp_check_omp_declare_reduction_data *udr_data
+ = (struct cp_check_omp_declare_reduction_data *) data;
+ if (SSA_VAR_P (*tp)
+ && !DECL_ARTIFICIAL (*tp)
+ && *tp != DECL_EXPR_DECL (udr_data->stmts[udr_data->combiner_p ? 0 : 3])
+ && *tp != DECL_EXPR_DECL (udr_data->stmts[udr_data->combiner_p ? 1 : 4]))
+ {
+ location_t loc = udr_data->loc;
+ if (udr_data->combiner_p)
+ error_at (loc, "%<#pragma omp declare reduction%> combiner refers to "
+ "variable %qD which is not %<omp_out%> nor %<omp_in%>",
+ *tp);
+ else
+ error_at (loc, "%<#pragma omp declare reduction%> initializer refers "
+ "to variable %qD which is not %<omp_priv%> nor "
+ "%<omp_orig%>",
+ *tp);
+ return *tp;
+ }
+ return NULL_TREE;
+}
+
+/* Diagnose violation of OpenMP #pragma omp declare reduction restrictions. */
+
+void
+cp_check_omp_declare_reduction (tree udr)
+{
+ tree type = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (udr)));
+ gcc_assert (TREE_CODE (type) == REFERENCE_TYPE);
+ type = TREE_TYPE (type);
+ int i;
+ location_t loc = DECL_SOURCE_LOCATION (udr);
+
+ if (type == error_mark_node)
+ return;
+ if (ARITHMETIC_TYPE_P (type))
+ {
+ static enum tree_code predef_codes[]
+ = { PLUS_EXPR, MULT_EXPR, MINUS_EXPR, BIT_AND_EXPR, BIT_XOR_EXPR,
+ BIT_IOR_EXPR, TRUTH_ANDIF_EXPR, TRUTH_ORIF_EXPR };
+ for (i = 0; i < 8; i++)
+ {
+ tree id = omp_reduction_id (predef_codes[i], NULL_TREE, NULL_TREE);
+ const char *n1 = IDENTIFIER_POINTER (DECL_NAME (udr));
+ const char *n2 = IDENTIFIER_POINTER (id);
+ if (strncmp (n1, n2, IDENTIFIER_LENGTH (id)) == 0
+ && (n1[IDENTIFIER_LENGTH (id)] == '~'
+ || n1[IDENTIFIER_LENGTH (id)] == '\0'))
+ break;
+ }
+
+ if (i == 8
+ && TREE_CODE (type) != COMPLEX_EXPR)
+ {
+ const char prefix_minmax[] = "omp declare reduction m";
+ size_t prefix_size = sizeof (prefix_minmax) - 1;
+ const char *n = IDENTIFIER_POINTER (DECL_NAME (udr));
+ if (strncmp (IDENTIFIER_POINTER (DECL_NAME (udr)),
+ prefix_minmax, prefix_size) == 0
+ && ((n[prefix_size] == 'i' && n[prefix_size + 1] == 'n')
+ || (n[prefix_size] == 'a' && n[prefix_size + 1] == 'x'))
+ && (n[prefix_size + 2] == '~' || n[prefix_size + 2] == '\0'))
+ i = 0;
+ }
+ if (i < 8)
+ {
+ error_at (loc, "predeclared arithmetic type %qT in "
+ "%<#pragma omp declare reduction%>", type);
+ return;
+ }
+ }
+ else if (TREE_CODE (type) == FUNCTION_TYPE
+ || TREE_CODE (type) == METHOD_TYPE
+ || TREE_CODE (type) == ARRAY_TYPE)
+ {
+ error_at (loc, "function or array type %qT in "
+ "%<#pragma omp declare reduction%>", type);
+ return;
+ }
+ else if (TREE_CODE (type) == REFERENCE_TYPE)
+ {
+ error_at (loc, "reference type %qT in %<#pragma omp declare reduction%>",
+ type);
+ return;
+ }
+ else if (TYPE_QUALS_NO_ADDR_SPACE (type))
+ {
+ error_at (loc, "const, volatile or __restrict qualified type %qT in "
+ "%<#pragma omp declare reduction%>", type);
+ return;
+ }
+
+ tree body = DECL_SAVED_TREE (udr);
+ if (body == NULL_TREE || TREE_CODE (body) != STATEMENT_LIST)
+ return;
+
+ tree_stmt_iterator tsi;
+ struct cp_check_omp_declare_reduction_data data;
+ memset (data.stmts, 0, sizeof data.stmts);
+ for (i = 0, tsi = tsi_start (body);
+ i < 7 && !tsi_end_p (tsi);
+ i++, tsi_next (&tsi))
+ data.stmts[i] = tsi_stmt (tsi);
+ data.loc = loc;
+ gcc_assert (tsi_end_p (tsi));
+ if (i >= 3)
+ {
+ gcc_assert (TREE_CODE (data.stmts[0]) == DECL_EXPR
+ && TREE_CODE (data.stmts[1]) == DECL_EXPR);
+ if (TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0])))
+ return;
+ data.combiner_p = true;
+ if (cp_walk_tree (&data.stmts[2], cp_check_omp_declare_reduction_r,
+ &data, NULL))
+ TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0])) = 1;
+ }
+ if (i >= 6)
+ {
+ gcc_assert (TREE_CODE (data.stmts[3]) == DECL_EXPR
+ && TREE_CODE (data.stmts[4]) == DECL_EXPR);
+ data.combiner_p = false;
+ if (cp_walk_tree (&data.stmts[5], cp_check_omp_declare_reduction_r,
+ &data, NULL)
+ || cp_walk_tree (&DECL_INITIAL (DECL_EXPR_DECL (data.stmts[3])),
+ cp_check_omp_declare_reduction_r, &data, NULL))
+ TREE_NO_WARNING (DECL_EXPR_DECL (data.stmts[0])) = 1;
+ if (i == 7)
+ gcc_assert (TREE_CODE (data.stmts[6]) == DECL_EXPR);
+ }
+}
+
+/* Helper function of finish_omp_clauses. Clone STMT as if we were making
+ an inline call. But, remap
+ the OMP_DECL1 VAR_DECL (omp_out resp. omp_orig) to PLACEHOLDER
+ and OMP_DECL2 VAR_DECL (omp_in resp. omp_priv) to DECL. */
+
+static tree
+clone_omp_udr (tree stmt, tree omp_decl1, tree omp_decl2,
+ tree decl, tree placeholder)
+{
+ copy_body_data id;
+ struct pointer_map_t *decl_map = pointer_map_create ();
+
+ *pointer_map_insert (decl_map, omp_decl1) = placeholder;
+ *pointer_map_insert (decl_map, omp_decl2) = decl;
+ memset (&id, 0, sizeof (id));
+ id.src_fn = DECL_CONTEXT (omp_decl1);
+ id.dst_fn = current_function_decl;
+ id.src_cfun = DECL_STRUCT_FUNCTION (id.src_fn);
+ id.decl_map = decl_map;
+
+ id.copy_decl = copy_decl_no_change;
+ id.transform_call_graph_edges = CB_CGE_DUPLICATE;
+ id.transform_new_cfg = true;
+ id.transform_return_to_modify = false;
+ id.transform_lang_insert_block = NULL;
+ id.eh_lp_nr = 0;
+ walk_tree (&stmt, copy_tree_body_r, &id, NULL);
+ pointer_map_destroy (decl_map);
+ return stmt;
+}
+
+/* Helper function of finish_omp_clauses, called via cp_walk_tree.
+ Find OMP_CLAUSE_PLACEHOLDER (passed in DATA) in *TP. */
+
+static tree
+find_omp_placeholder_r (tree *tp, int *, void *data)
+{
+ if (*tp == (tree) data)
+ return *tp;
+ return NULL_TREE;
+}
+
+/* Helper function of finish_omp_clauses. Handle OMP_CLAUSE_REDUCTION C.
+ Return true if there is some error and the clause should be removed. */
+
+static bool
+finish_omp_reduction_clause (tree c, bool *need_default_ctor, bool *need_dtor)
+{
+ tree t = OMP_CLAUSE_DECL (c);
+ bool predefined = false;
+ tree type = TREE_TYPE (t);
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+ if (type == error_mark_node)
+ return true;
+ else if (ARITHMETIC_TYPE_P (type))
+ switch (OMP_CLAUSE_REDUCTION_CODE (c))
+ {
+ case PLUS_EXPR:
+ case MULT_EXPR:
+ case MINUS_EXPR:
+ predefined = true;
+ break;
+ case MIN_EXPR:
+ case MAX_EXPR:
+ if (TREE_CODE (type) == COMPLEX_TYPE)
+ break;
+ predefined = true;
+ break;
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ if (FLOAT_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
+ break;
+ predefined = true;
+ break;
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_ORIF_EXPR:
+ if (FLOAT_TYPE_P (type))
+ break;
+ predefined = true;
+ break;
+ default:
+ break;
+ }
+ else if (TREE_CODE (type) == ARRAY_TYPE || TYPE_READONLY (type))
+ {
+ error ("%qE has invalid type for %<reduction%>", t);
+ return true;
+ }
+ else if (!processing_template_decl)
+ {
+ t = require_complete_type (t);
+ if (t == error_mark_node)
+ return true;
+ OMP_CLAUSE_DECL (c) = t;
+ }
+
+ if (predefined)
+ {
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE;
+ return false;
+ }
+ else if (processing_template_decl)
+ return false;
+
+ tree id = OMP_CLAUSE_REDUCTION_PLACEHOLDER (c);
+
+ type = TYPE_MAIN_VARIANT (TREE_TYPE (t));
+ if (TREE_CODE (type) == REFERENCE_TYPE)
+ type = TREE_TYPE (type);
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = NULL_TREE;
+ if (id == NULL_TREE)
+ id = omp_reduction_id (OMP_CLAUSE_REDUCTION_CODE (c),
+ NULL_TREE, NULL_TREE);
+ id = omp_reduction_lookup (OMP_CLAUSE_LOCATION (c), id, type, NULL, NULL);
+ if (id)
+ {
+ if (id == error_mark_node)
+ return true;
+ id = OVL_CURRENT (id);
+ mark_used (id);
+ tree body = DECL_SAVED_TREE (id);
+ if (TREE_CODE (body) == STATEMENT_LIST)
+ {
+ tree_stmt_iterator tsi;
+ tree placeholder = NULL_TREE;
+ int i;
+ tree stmts[7];
+ tree atype = TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (id)));
+ atype = TREE_TYPE (atype);
+ bool need_static_cast = !same_type_p (type, atype);
+ memset (stmts, 0, sizeof stmts);
+ for (i = 0, tsi = tsi_start (body);
+ i < 7 && !tsi_end_p (tsi);
+ i++, tsi_next (&tsi))
+ stmts[i] = tsi_stmt (tsi);
+ gcc_assert (tsi_end_p (tsi));
+
+ if (i >= 3)
+ {
+ gcc_assert (TREE_CODE (stmts[0]) == DECL_EXPR
+ && TREE_CODE (stmts[1]) == DECL_EXPR);
+ placeholder = build_lang_decl (VAR_DECL, NULL_TREE, type);
+ DECL_ARTIFICIAL (placeholder) = 1;
+ DECL_IGNORED_P (placeholder) = 1;
+ OMP_CLAUSE_REDUCTION_PLACEHOLDER (c) = placeholder;
+ if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[0])))
+ cxx_mark_addressable (placeholder);
+ if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[1]))
+ && TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c)))
+ != REFERENCE_TYPE)
+ cxx_mark_addressable (OMP_CLAUSE_DECL (c));
+ tree omp_out = placeholder;
+ tree omp_in = convert_from_reference (OMP_CLAUSE_DECL (c));
+ if (need_static_cast)
+ {
+ tree rtype = build_reference_type (atype);
+ omp_out = build_static_cast (rtype, omp_out,
+ tf_warning_or_error);
+ omp_in = build_static_cast (rtype, omp_in,
+ tf_warning_or_error);
+ if (omp_out == error_mark_node || omp_in == error_mark_node)
+ return true;
+ omp_out = convert_from_reference (omp_out);
+ omp_in = convert_from_reference (omp_in);
+ }
+ OMP_CLAUSE_REDUCTION_MERGE (c)
+ = clone_omp_udr (stmts[2], DECL_EXPR_DECL (stmts[0]),
+ DECL_EXPR_DECL (stmts[1]), omp_in, omp_out);
+ }
+ if (i >= 6)
+ {
+ gcc_assert (TREE_CODE (stmts[3]) == DECL_EXPR
+ && TREE_CODE (stmts[4]) == DECL_EXPR);
+ if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[3])))
+ cxx_mark_addressable (OMP_CLAUSE_DECL (c));
+ if (TREE_ADDRESSABLE (DECL_EXPR_DECL (stmts[4])))
+ cxx_mark_addressable (placeholder);
+ tree omp_priv = convert_from_reference (OMP_CLAUSE_DECL (c));
+ tree omp_orig = placeholder;
+ if (need_static_cast)
+ {
+ if (i == 7)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "user defined reduction with constructor "
+ "initializer for base class %qT", atype);
+ return true;
+ }
+ tree rtype = build_reference_type (atype);
+ omp_priv = build_static_cast (rtype, omp_priv,
+ tf_warning_or_error);
+ omp_orig = build_static_cast (rtype, omp_orig,
+ tf_warning_or_error);
+ if (omp_priv == error_mark_node
+ || omp_orig == error_mark_node)
+ return true;
+ omp_priv = convert_from_reference (omp_priv);
+ omp_orig = convert_from_reference (omp_orig);
+ }
+ if (i == 6)
+ *need_default_ctor = true;
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = clone_omp_udr (stmts[5], DECL_EXPR_DECL (stmts[4]),
+ DECL_EXPR_DECL (stmts[3]),
+ omp_priv, omp_orig);
+ if (cp_walk_tree (&OMP_CLAUSE_REDUCTION_INIT (c),
+ find_omp_placeholder_r, placeholder, NULL))
+ OMP_CLAUSE_REDUCTION_OMP_ORIG_REF (c) = 1;
+ }
+ else if (i >= 3)
+ {
+ if (CLASS_TYPE_P (type) && !pod_type_p (type))
+ *need_default_ctor = true;
+ else
+ {
+ tree init;
+ tree v = convert_from_reference (t);
+ if (AGGREGATE_TYPE_P (TREE_TYPE (v)))
+ init = build_constructor (TREE_TYPE (v), NULL);
+ else
+ init = fold_convert (TREE_TYPE (v), integer_zero_node);
+ OMP_CLAUSE_REDUCTION_INIT (c)
+ = build2 (INIT_EXPR, TREE_TYPE (v), v, init);
+ }
+ }
+ }
+ }
+ if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
+ *need_dtor = true;
+ else
+ {
+ error ("user defined reduction not found for %qD", t);
+ return true;
+ }
+ return false;
+}
+
+/* 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;
+ bitmap_head aligned_head;
+ tree c, t, *pc = &clauses;
+ bool branch_seen = false;
+ bool copyprivate_seen = false;
+
+ 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);
+ bitmap_initialize (&aligned_head, &bitmap_default_obstack);
+
+ for (pc = &clauses, c = clauses; c ; c = *pc)
+ {
+ bool remove = false;
+
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ case OMP_CLAUSE_SHARED:
+ goto check_dup_generic;
+ case OMP_CLAUSE_PRIVATE:
+ goto check_dup_generic;
+ case OMP_CLAUSE_REDUCTION:
+ goto check_dup_generic;
+ case OMP_CLAUSE_COPYPRIVATE:
+ copyprivate_seen = true;
+ goto check_dup_generic;
+ case OMP_CLAUSE_COPYIN:
+ goto check_dup_generic;
+ case OMP_CLAUSE_LINEAR:
+ t = OMP_CLAUSE_DECL (c);
+ if (!type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (t))
+ && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
+ {
+ error ("linear clause applied to non-integral non-pointer "
+ "variable with %qT type", TREE_TYPE (t));
+ remove = true;
+ break;
+ }
+ t = OMP_CLAUSE_LINEAR_STEP (c);
+ if (t == NULL_TREE)
+ t = integer_one_node;
+ if (t == error_mark_node)
+ {
+ remove = true;
+ break;
+ }
+ else if (!type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error ("linear step expression must be integral");
+ remove = true;
+ break;
+ }
+ else
+ {
+ t = mark_rvalue_use (t);
+ if (!processing_template_decl)
+ {
+ if (TREE_CODE (OMP_CLAUSE_DECL (c)) == PARM_DECL)
+ t = maybe_constant_value (t);
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
+ if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c)))
+ == POINTER_TYPE)
+ {
+ t = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR,
+ OMP_CLAUSE_DECL (c), t);
+ t = fold_build2_loc (OMP_CLAUSE_LOCATION (c),
+ MINUS_EXPR, sizetype, t,
+ OMP_CLAUSE_DECL (c));
+ if (t == error_mark_node)
+ {
+ remove = true;
+ break;
+ }
+ }
+ }
+ OMP_CLAUSE_LINEAR_STEP (c) = t;
+ }
+ goto check_dup_generic;
+ check_dup_generic:
+ t = OMP_CLAUSE_DECL (c);
+ if (!VAR_P (t) && TREE_CODE (t) != PARM_DECL)
+ {
+ if (processing_template_decl)
+ break;
+ if (DECL_P (t))
+ error ("%qD is not a variable in clause %qs", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ else
+ error ("%qE is not a variable in clause %qs", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ 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 (!VAR_P (t) && 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 (!VAR_P (t) && 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_SIMDLEN:
+ case OMP_CLAUSE_SAFELEN:
+ t = OMP_CLAUSE_OPERAND (c, 0);
+ if (t == error_mark_node)
+ remove = true;
+ else if (!type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error ("%qs length expression must be integral",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ else
+ {
+ t = mark_rvalue_use (t);
+ t = maybe_constant_value (t);
+ if (!processing_template_decl)
+ {
+ if (TREE_CODE (t) != INTEGER_CST
+ || tree_int_cst_sgn (t) != 1)
+ {
+ error ("%qs length expression must be positive constant"
+ " integer expression",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ }
+ OMP_CLAUSE_OPERAND (c, 0) = t;
+ }
+ break;
+
+ case OMP_CLAUSE_NUM_TEAMS:
+ t = OMP_CLAUSE_NUM_TEAMS_EXPR (c);
+ if (t == error_mark_node)
+ remove = true;
+ else if (!type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error ("%<num_teams%> 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_TEAMS_EXPR (c) = t;
+ }
+ break;
+
+ case OMP_CLAUSE_THREAD_LIMIT:
+ t = OMP_CLAUSE_THREAD_LIMIT_EXPR (c);
+ if (t == error_mark_node)
+ remove = true;
+ else if (!type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error ("%<thread_limit%> 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_THREAD_LIMIT_EXPR (c) = t;
+ }
+ break;
+
+ case OMP_CLAUSE_DEVICE:
+ t = OMP_CLAUSE_DEVICE_ID (c);
+ if (t == error_mark_node)
+ remove = true;
+ else if (!type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error ("%<device%> id 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_DEVICE_ID (c) = t;
+ }
+ break;
+
+ case OMP_CLAUSE_DIST_SCHEDULE:
+ t = OMP_CLAUSE_DIST_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 ("%<dist_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_DIST_SCHEDULE_CHUNK_EXPR (c) = t;
+ }
+ break;
+
+ case OMP_CLAUSE_ALIGNED:
+ 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 %<aligned%> clause", t);
+ else
+ error ("%qE is not a variable in %<aligned%> clause", t);
+ remove = true;
+ }
+ else if (!type_dependent_expression_p (t)
+ && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE
+ && TREE_CODE (TREE_TYPE (t)) != ARRAY_TYPE
+ && (TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE
+ || (!POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (t)))
+ && (TREE_CODE (TREE_TYPE (TREE_TYPE (t)))
+ != ARRAY_TYPE))))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qE in %<aligned%> clause is neither a pointer nor "
+ "an array nor a reference to pointer or array", t);
+ remove = true;
+ }
+ else if (bitmap_bit_p (&aligned_head, DECL_UID (t)))
+ {
+ error ("%qD appears more than once in %<aligned%> clauses", t);
+ remove = true;
+ }
+ else
+ bitmap_set_bit (&aligned_head, DECL_UID (t));
+ t = OMP_CLAUSE_ALIGNED_ALIGNMENT (c);
+ if (t == error_mark_node)
+ remove = true;
+ else if (t == NULL_TREE)
+ break;
+ else if (!type_dependent_expression_p (t)
+ && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+ {
+ error ("%<aligned%> clause alignment expression must "
+ "be integral");
+ remove = true;
+ }
+ else
+ {
+ t = mark_rvalue_use (t);
+ t = maybe_constant_value (t);
+ if (!processing_template_decl)
+ {
+ if (TREE_CODE (t) != INTEGER_CST
+ || tree_int_cst_sgn (t) != 1)
+ {
+ error ("%<aligned%> clause alignment expression must be "
+ "positive constant integer expression");
+ remove = true;
+ }
+ }
+ OMP_CLAUSE_ALIGNED_ALIGNMENT (c) = t;
+ }
+ break;
+
+ case OMP_CLAUSE_DEPEND:
+ t = OMP_CLAUSE_DECL (c);
+ if (TREE_CODE (t) == TREE_LIST)
+ {
+ if (handle_omp_array_sections (c))
+ remove = true;
+ break;
+ }
+ if (t == error_mark_node)
+ remove = true;
+ else 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 %<depend%> clause", t);
+ else
+ error ("%qE is not a variable in %<depend%> clause", t);
+ remove = true;
+ }
+ else if (!processing_template_decl
+ && !cxx_mark_addressable (t))
+ remove = true;
+ break;
+
+ case OMP_CLAUSE_MAP:
+ case OMP_CLAUSE_TO:
+ case OMP_CLAUSE_FROM:
+ t = OMP_CLAUSE_DECL (c);
+ if (TREE_CODE (t) == TREE_LIST)
+ {
+ if (handle_omp_array_sections (c))
+ remove = true;
+ else
+ {
+ t = OMP_CLAUSE_DECL (c);
+ if (!cp_omp_mappable_type (TREE_TYPE (t)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "array section does not have mappable type "
+ "in %qs clause",
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ }
+ break;
+ }
+ if (t == error_mark_node)
+ remove = true;
+ else if (TREE_CODE (t) != VAR_DECL && TREE_CODE (t) != PARM_DECL)
+ {
+ if (processing_template_decl)
+ break;
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)
+ break;
+ if (DECL_P (t))
+ error ("%qD is not a variable in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ else
+ error ("%qE is not a variable in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ else if (TREE_CODE (t) == VAR_DECL && DECL_THREAD_LOCAL_P (t))
+ {
+ error ("%qD is threadprivate variable in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ else if (!processing_template_decl
+ && TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE
+ && !cxx_mark_addressable (t))
+ remove = true;
+ else if (!(OMP_CLAUSE_CODE (c) == OMP_CLAUSE_MAP
+ && OMP_CLAUSE_MAP_KIND (c) == OMP_CLAUSE_MAP_POINTER)
+ && !cp_omp_mappable_type ((TREE_CODE (TREE_TYPE (t))
+ == REFERENCE_TYPE)
+ ? TREE_TYPE (TREE_TYPE (t))
+ : TREE_TYPE (t)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD does not have a mappable type in %qs clause", t,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ else if (bitmap_bit_p (&generic_head, DECL_UID (t)))
+ {
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_MAP)
+ error ("%qD appears more than once in motion clauses", t);
+ else
+ error ("%qD appears more than once in map clauses", t);
+ remove = true;
+ }
+ else
+ bitmap_set_bit (&generic_head, DECL_UID (t));
+ break;
+
+ case OMP_CLAUSE_UNIFORM:
+ t = OMP_CLAUSE_DECL (c);
+ if (TREE_CODE (t) != PARM_DECL)
+ {
+ if (processing_template_decl)
+ break;
+ if (DECL_P (t))
+ error ("%qD is not an argument in %<uniform%> clause", t);
+ else
+ error ("%qE is not an argument in %<uniform%> clause", t);
+ remove = true;
+ break;
+ }
+ goto check_dup_generic;
+
+ case OMP_CLAUSE_NOWAIT:
+ case OMP_CLAUSE_ORDERED:
+ case OMP_CLAUSE_DEFAULT:
+ case OMP_CLAUSE_UNTIED:
+ case OMP_CLAUSE_COLLAPSE:
+ case OMP_CLAUSE_MERGEABLE:
+ case OMP_CLAUSE_PARALLEL:
+ case OMP_CLAUSE_FOR:
+ case OMP_CLAUSE_SECTIONS:
+ case OMP_CLAUSE_TASKGROUP:
+ case OMP_CLAUSE_PROC_BIND:
+ break;
+
+ case OMP_CLAUSE_INBRANCH:
+ case OMP_CLAUSE_NOTINBRANCH:
+ if (branch_seen)
+ {
+ error ("%<inbranch%> clause is incompatible with "
+ "%<notinbranch%>");
+ remove = true;
+ }
+ branch_seen = true;
+ 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;
+ bool need_dtor = false;
+ tree type, inner_type;
+
+ switch (c_kind)
+ {
+ case OMP_CLAUSE_SHARED:
+ need_implicitly_determined = true;
+ break;
+ case OMP_CLAUSE_PRIVATE:
+ need_complete_non_reference = true;
+ need_default_ctor = true;
+ need_dtor = true;
+ need_implicitly_determined = true;
+ break;
+ case OMP_CLAUSE_FIRSTPRIVATE:
+ need_complete_non_reference = true;
+ need_copy_ctor = true;
+ need_dtor = true;
+ need_implicitly_determined = true;
+ break;
+ case OMP_CLAUSE_LASTPRIVATE:
+ need_complete_non_reference = true;
+ need_copy_assignment = true;
+ need_implicitly_determined = true;
+ break;
+ case OMP_CLAUSE_REDUCTION:
+ need_implicitly_determined = true;
+ break;
+ case OMP_CLAUSE_COPYPRIVATE:
+ need_copy_assignment = true;
+ break;
+ case OMP_CLAUSE_COPYIN:
+ need_copy_assignment = true;
+ break;
+ case OMP_CLAUSE_NOWAIT:
+ if (copyprivate_seen)
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<nowait%> clause must not be used together "
+ "with %<copyprivate%>");
+ *pc = OMP_CLAUSE_CHAIN (c);
+ continue;
+ }
+ /* FALLTHRU */
+ default:
+ pc = &OMP_CLAUSE_CHAIN (c);
+ continue;
+ }
+
+ t = OMP_CLAUSE_DECL (c);
+ if (processing_template_decl
+ && !VAR_P (t) && 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;
+ need_dtor = true;
+ }
+ break;
+
+ case OMP_CLAUSE_REDUCTION:
+ if (finish_omp_reduction_clause (c, &need_default_ctor,
+ &need_dtor))
+ remove = true;
+ else
+ t = OMP_CLAUSE_DECL (c);
+ break;
+
+ case OMP_CLAUSE_COPYIN:
+ if (!VAR_P (t) || !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,
+ omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ remove = true;
+ }
+ }
+ if (need_implicitly_determined)
+ {
+ const char *share_name = NULL;
+
+ if (VAR_P (t) && 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, omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
+ 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);
+
+ if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+ && TREE_CODE (inner_type) == REFERENCE_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 || need_dtor)
+ && !type_dependent_expression_p (t)
+ && cxx_omp_create_clause_info (c, inner_type, need_default_ctor,
+ need_copy_ctor, need_copy_assignment,
+ need_dtor))
+ 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 (!VAR_P (v))
+ 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, enum tree_code code, 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 (code);
+
+ 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 (code == OMP_SIMD)
+ {
+ error_at (elocus, "%<#pragma omp simd%> used with class "
+ "iteration variable %qE", decl);
+ return NULL;
+ }
+ 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))
+ && !TYPE_PTR_P (TREE_TYPE (decl)))
+ {
+ 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, code, 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, bool seq_cst)
+{
+ 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)
+ {
+ bool swapped = false;
+ if (rhs1 && cp_tree_equal (lhs, rhs))
+ {
+ tree tem = rhs;
+ rhs = rhs1;
+ rhs1 = tem;
+ swapped = !commutative_tree_code (opcode);
+ }
+ if (rhs1 && !cp_tree_equal (lhs, rhs1))
+ {
+ if (code == OMP_ATOMIC)
+ error ("%<#pragma omp atomic update%> uses two different "
+ "expressions for memory");
+ else
+ error ("%<#pragma omp atomic capture%> uses two different "
+ "expressions for memory");
+ return;
+ }
+ if (lhs1 && !cp_tree_equal (lhs, lhs1))
+ {
+ if (code == OMP_ATOMIC)
+ error ("%<#pragma omp atomic update%> uses two different "
+ "expressions for memory");
+ else
+ error ("%<#pragma omp atomic capture%> uses two different "
+ "expressions for memory");
+ return;
+ }
+ stmt = c_finish_omp_atomic (input_location, code, opcode, lhs, rhs,
+ v, lhs1, rhs1, swapped, seq_cst);
+ 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);
+ OMP_ATOMIC_SEQ_CST (stmt) = seq_cst;
+ 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);
+ OMP_ATOMIC_SEQ_CST (stmt) = seq_cst;
+ stmt = build2 (MODIFY_EXPR, void_type_node, orig_v, stmt);
+ }
+ }
+ stmt = build2 (OMP_ATOMIC, void_type_node, integer_zero_node, stmt);
+ OMP_ATOMIC_SEQ_CST (stmt) = seq_cst;
+ }
+ finish_expr_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);
+}
+
+void
+finish_omp_cancel (tree clauses)
+{
+ tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCEL);
+ int mask = 0;
+ if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL))
+ mask = 1;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_FOR))
+ mask = 2;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS))
+ mask = 4;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP))
+ mask = 8;
+ else
+ {
+ error ("%<#pragma omp cancel must specify one of "
+ "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> clauses");
+ return;
+ }
+ vec<tree, va_gc> *vec = make_tree_vector ();
+ tree ifc = find_omp_clause (clauses, OMP_CLAUSE_IF);
+ if (ifc != NULL_TREE)
+ {
+ tree type = TREE_TYPE (OMP_CLAUSE_IF_EXPR (ifc));
+ ifc = fold_build2_loc (OMP_CLAUSE_LOCATION (ifc), NE_EXPR,
+ boolean_type_node, OMP_CLAUSE_IF_EXPR (ifc),
+ build_zero_cst (type));
+ }
+ else
+ ifc = boolean_true_node;
+ vec->quick_push (build_int_cst (integer_type_node, mask));
+ vec->quick_push (ifc);
+ tree stmt = finish_call_expr (fn, &vec, false, false, tf_warning_or_error);
+ release_tree_vector (vec);
+ finish_expr_stmt (stmt);
+}
+
+void
+finish_omp_cancellation_point (tree clauses)
+{
+ tree fn = builtin_decl_explicit (BUILT_IN_GOMP_CANCELLATION_POINT);
+ int mask = 0;
+ if (find_omp_clause (clauses, OMP_CLAUSE_PARALLEL))
+ mask = 1;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_FOR))
+ mask = 2;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_SECTIONS))
+ mask = 4;
+ else if (find_omp_clause (clauses, OMP_CLAUSE_TASKGROUP))
+ mask = 8;
+ else
+ {
+ error ("%<#pragma omp cancellation point must specify one of "
+ "%<parallel%>, %<for%>, %<sections%> or %<taskgroup%> clauses");
+ return;
+ }
+ vec<tree, va_gc> *vec
+ = make_tree_vector_single (build_int_cst (integer_type_node, mask));
+ 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);
+ /* This may not be true when the STATEMENT_LIST is empty. */
+ if (EXPR_P (body))
+ 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);
+}
+
+/* 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);
+ if (EXPR_P (expr))
+ 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");
+ if (require_potential_rvalue_constant_expression (condition))
+ 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 (invalid_nonstatic_memfn_p (expr, complain))
+ return error_mark_node;
+
+ if (type_unknown_p (expr))
+ {
+ if (complain & tf_error)
+ error ("decltype cannot resolve address of overloaded function");
+ 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 (VAR_P (expr)
+ && 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 (identifier_p (expr))
+ expr = lookup_name (expr);
+
+ if (INDIRECT_REF_P (expr))
+ /* 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));
+ }
+ }
+
+ if (cxx_dialect >= cxx1y && array_of_runtime_bound_p (type)
+ && (flag_iso || warn_vla > 0))
+ {
+ if (complain & tf_warning_or_error)
+ pedwarn (input_location, OPT_Wvla,
+ "taking decltype of array of runtime bound");
+ else
+ return error_mark_node;
+ }
+
+ 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)
+ && (same_type_ignoring_top_level_qualifiers_p (type1, 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 (VAR_P (decl) && DECL_DECLARED_CONSTEXPR_P (decl)
+ && !processing_template_decl)
+ {
+ tree stype = strip_array_types (type);
+ if (CLASS_TYPE_P (stype) && !COMPLETE_TYPE_P (complete_type (stype)))
+ /* 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)
+{
+ bool ret = true;
+
+ if (DECL_INHERITED_CTOR_BASE (fun)
+ && TREE_CODE (fun) == TEMPLATE_DECL)
+ {
+ ret = false;
+ if (complain)
+ error ("inherited constructor %qD is not constexpr",
+ get_inherited_ctor (fun));
+ }
+ else
+ {
+ for (tree parm = FUNCTION_FIRST_USER_PARM (fun);
+ parm != NULL_TREE; 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. */
+ auto_vec<tree, 2> fields;
+ do
+ {
+ fields.safe_push (TREE_OPERAND (member, 1));
+ member = TREE_OPERAND (member, 0);
+ }
+ while (ANON_AGGR_TYPE_P (TREE_TYPE (member))
+ && TREE_CODE (member) == COMPONENT_REF);
+
+ /* 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());
+ 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 = break_out_target_exprs (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 = break_out_target_exprs (t);
+ }
+ else if (TREE_CODE (t) == DECL_EXPR)
+ /* Declaring a temporary, don't add it to the CONSTRUCTOR. */
+ return true;
+ else
+ gcc_unreachable ();
+ if (INDIRECT_REF_P (member))
+ 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 (BIND_EXPR_VARS (t))
+ {
+ ok = false;
+ break;
+ }
+ 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 break_out_target_exprs (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 accommodate 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 construction, 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_LOC (t, input_location);
+ 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 constructor/op=. */
+ if (trivial_fn_p (fun))
+ {
+ if (call_expr_nargs (t) == 2)
+ {
+ 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);
+ }
+ else if (TREE_CODE (t) == AGGR_INIT_EXPR
+ && AGGR_INIT_ZERO_FIRST (t))
+ return build_zero_init (DECL_CONTEXT (fun), NULL_TREE, false);
+ }
+
+ /* 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 (TYPE_PTR_P (TREE_TYPE (ob_arg))
+ && 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)
+{
+ if (TREE_CODE (t) == PTRMEM_CST)
+ /* Even if we can't lower this yet, it's constant. */
+ return true;
+ /* 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_to_shwi (index);
+ 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) != VECTOR_CST
+ && 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;
+
+ if (TREE_CODE (whole) == VECTOR_CST)
+ return fold_ternary (BIT_FIELD_REF, TREE_TYPE (t), whole,
+ TREE_OPERAND (t, 1), TREE_OPERAND (t, 2));
+
+ start = TREE_OPERAND (t, 2);
+ istart = tree_to_shwi (start);
+ isize = tree_to_shwi (TREE_OPERAND (t, 1));
+ 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
+ && tree_fits_shwi_p (bitpos)
+ && tree_fits_shwi_p (DECL_SIZE (field)))
+ {
+ HOST_WIDE_INT bit = tree_to_shwi (bitpos);
+ HOST_WIDE_INT sz = tree_to_shwi (DECL_SIZE (field));
+ 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_to_shwi (array_type_nelts (atype));
+ 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. */
+ 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);
+ eltinit = force_rvalue (eltinit, tf_warning_or_error);
+ 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_to_shwi (op01);
+ tree part_width = TYPE_SIZE (type);
+ unsigned HOST_WIDE_INT part_widthi = tree_to_shwi (part_width)/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) == 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 >= cxx11 && !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);
+ }
+}
+
+/* Subroutine of cxx_eval_constant_expression.
+ Like cxx_eval_unary_expression, except for trinary expressions. */
+
+static tree
+cxx_eval_trinary_expression (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;
+
+ 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);
+ VERIFY_CONSTANT (args[i]);
+ }
+
+ val = fold_ternary_loc (EXPR_LOCATION (t), TREE_CODE (t), TREE_TYPE (t),
+ args[0], args[1], args[2]);
+ if (val == NULL_TREE)
+ return t;
+ VERIFY_CONSTANT (val);
+ return val;
+}
+
+/* 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 LTGT_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:
+ if (is_overloaded_fn (t))
+ {
+ /* We can only get here in checking mode via
+ build_non_dependent_expr, because any expression that
+ calls or takes the address of the function will have
+ pulled a FUNCTION_DECL out of the COMPONENT_REF. */
+ gcc_checking_assert (allow_non_constant || errorcount);
+ *non_constant_p = true;
+ return t;
+ }
+ 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 FMA_EXPR:
+ case VEC_PERM_EXPR:
+ r = cxx_eval_trinary_expression (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 (POINTER_TYPE_P (TREE_TYPE (t))
+ && TREE_CODE (op) == INTEGER_CST
+ && !integer_zerop (op))
+ {
+ if (!allow_non_constant)
+ error_at (EXPR_LOC_OR_LOC (t, input_location),
+ "reinterpret_cast from integer to pointer");
+ *non_constant_p = true;
+ 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_LOC (t, input_location),
+ "expression %qE is not a constant-expression", t);
+ *non_constant_p = true;
+ break;
+
+ default:
+ internal_error ("unexpected expression %qE of kind %s", t,
+ get_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 (instantiation_dependent_expression_p (t)
+ || type_unknown_p (t)
+ || BRACE_ENCLOSED_INITIALIZER_P (t)
+ || !potential_constant_expression (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 occurrences 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 LABEL_EXPR:
+ 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_LOC (t, input_location),
+ "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_CONTEXT (x) == NULL_TREE
+ || 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);
+ if (POINTER_TYPE_P (TREE_TYPE (t))
+ && TREE_CODE (from) == INTEGER_CST
+ && !integer_zerop (from))
+ {
+ if (flags & tf_error)
+ error_at (EXPR_LOC_OR_LOC (t, input_location),
+ "reinterpret_cast from integer to pointer");
+ return false;
+ }
+ 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 (DECL_CONTEXT (x)
+ && !DECL_DECLARED_CONSTEXPR_P (DECL_CONTEXT (x)))
+ {
+ if (flags & tf_error)
+ error ("use of %<this%> in a constant expression");
+ return false;
+ }
+ 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:
+ case OMP_ATOMIC:
+ case OMP_ATOMIC_READ:
+ case OMP_ATOMIC_CAPTURE_OLD:
+ case OMP_ATOMIC_CAPTURE_NEW:
+ /* 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 < cxx11
+ && !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 CILK_SYNC_STMT:
+ case CILK_SPAWN_STMT:
+ case ARRAY_NOTATION_REF:
+ return false;
+
+ 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", get_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);
+}
+
+/* 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;
+}
+
+#include "gt-cp-semantics.h"