summaryrefslogtreecommitdiff
path: root/gcc/cp/pt.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/pt.c')
-rw-r--r--gcc/cp/pt.c208
1 files changed, 208 insertions, 0 deletions
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 21d4039b623..db5eac54ad4 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
+#include "print-tree.h"
#include "stringpool.h"
#include "varasm.h"
#include "attribs.h"
@@ -9823,6 +9824,197 @@ gen_elem_of_pack_expansion_instantiation (tree pattern,
return t;
}
+tree
+expand_empty_fold (tree t, tsubst_flags_t complain)
+{
+ tree_code code = (tree_code)TREE_INT_CST_LOW (TREE_OPERAND (t, 0));
+ switch (code)
+ {
+ case PLUS_EXPR:
+ return build_value_init (integer_type_node, complain);
+ case MULT_EXPR:
+ return build_one_cst (integer_type_node);
+ case BIT_AND_EXPR:
+ return build_minus_one_cst (integer_type_node);
+ case BIT_IOR_EXPR:
+ return build_value_init (integer_type_node, complain);
+ case BIT_XOR_EXPR:
+ return build_value_init (integer_type_node, complain);
+ case TRUTH_ANDIF_EXPR:
+ return boolean_true_node;
+ case TRUTH_ORIF_EXPR:
+ return boolean_false_node;
+ case COMPOUND_EXPR:
+ return void_node;
+ default:
+ break;
+ }
+
+ // TODO: Improve diagnostics.
+ if (complain & tf_error)
+ error ("fold of empty expansion");
+ return error_mark_node;
+}
+
+/* Given a fold-expression T and a current LEFT and RIGHT operand,
+ form an expression that combines the two terms using the
+ operator of T. */
+
+static tree
+fold_expression (tree t, tree left, tree right, tsubst_flags_t complain)
+{
+ tree op = FOLD_EXPR_OP (t);
+ tree_code code = (tree_code)TREE_INT_CST_LOW (op);
+
+ // Handle compound assignment operators.
+ if (FOLD_EXPR_MODIFY_P (t))
+ return build_x_modify_expr (input_location, left, code, right, complain);
+
+ switch (code)
+ {
+ case COMPOUND_EXPR:
+ return build_x_compound_expr (input_location, left, right, complain);
+ case DOTSTAR_EXPR:
+ return build_m_component_ref (left, right, complain);
+ default:
+ return build_x_binary_op (input_location, code,
+ left, TREE_CODE (left),
+ right, TREE_CODE (right),
+ /*overload=*/NULL,
+ complain);
+ }
+}
+
+/* Substitute ARGS into the pack of a fold expression T. */
+
+static inline tree
+tsubst_fold_expr_pack (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+ return tsubst_pack_expansion (FOLD_EXPR_PACK (t), args, complain, in_decl);
+}
+
+/* Substitute ARGS into the pack of a fold expression T. */
+
+static inline tree
+tsubst_fold_expr_init (tree t, tree args, tsubst_flags_t complain, tree in_decl)
+{
+ return tsubst_expr (FOLD_EXPR_INIT (t), args, complain, in_decl, false);
+}
+
+/* Expand a PACK of arguments into a grouped as left fold.
+ Given a pack containing elements A0, A1, ..., An and an
+ operator @, this builds the expression:
+
+ ((A0 @ A1) @ A2) ... @ An
+
+ Note that PACK must not be empty.
+
+ The operator is defined by the original fold expression T. */
+
+static tree
+expand_left_fold (tree t, tree pack, tsubst_flags_t complain)
+{
+ tree left = TREE_VEC_ELT (pack, 0);
+ for (int i = 1; i < TREE_VEC_LENGTH (pack); ++i)
+ {
+ tree right = TREE_VEC_ELT (pack, i);
+ left = fold_expression (t, left, right, complain);
+ }
+ return left;
+}
+
+/* Sbustitute into a unary left fold expression. */
+
+static tree
+tsubst_unary_left_fold (tree t, tree args, tsubst_flags_t complain,
+ tree in_decl)
+{
+ tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
+ if (TREE_VEC_LENGTH (pack) == 0)
+ return expand_empty_fold (t, complain);
+ else
+ return expand_left_fold (t, pack, complain);
+}
+
+/* Substitute into a binary left fold expression.
+
+ Do ths by building a single (non-empty) vector of argumnts and
+ building the expression from those elements. */
+
+static tree
+tsubst_binary_left_fold (tree t, tree args, tsubst_flags_t complain,
+ tree in_decl)
+{
+ tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
+ tree init = tsubst_fold_expr_init (t, args, complain, in_decl);
+
+ tree vec = make_tree_vec (TREE_VEC_LENGTH (pack) + 1);
+ TREE_VEC_ELT (vec, 0) = init;
+ for (int i = 0; i < TREE_VEC_LENGTH (pack); ++i)
+ TREE_VEC_ELT (vec, i + 1) = TREE_VEC_ELT (pack, i);
+
+ return expand_left_fold (t, vec, complain);
+}
+
+/* Expand a PACK of arguments into a grouped as right fold.
+ Given a pack containing elementns A0, A1, ..., and an
+ operator @, this builds the expression:
+
+ A0@ ... (An-2 @ (An-1 @ An))
+
+ Note that PACK must not be empty.
+
+ The operator is defined by the original fold expression T. */
+
+tree
+expand_right_fold (tree t, tree pack, tsubst_flags_t complain)
+{
+ // Build the expression.
+ int n = TREE_VEC_LENGTH (pack);
+ tree right = TREE_VEC_ELT (pack, n - 1);
+ for (--n; n != 0; --n)
+ {
+ tree left = TREE_VEC_ELT (pack, n - 1);
+ right = fold_expression (t, left, right, complain);
+ }
+ return right;
+}
+
+/* Substitute into a unary right fold expression. */
+
+static tree
+tsubst_unary_right_fold (tree t, tree args, tsubst_flags_t complain,
+ tree in_decl)
+{
+ tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
+ if (TREE_VEC_LENGTH (pack) == 0)
+ return expand_empty_fold (t, complain);
+ else
+ return expand_right_fold (t, pack, complain);
+}
+
+/* Substitute into a binary right fold expression.
+
+ Do ths by building a single (non-empty) vector of arguments and
+ building the expression from those elements. */
+
+static tree
+tsubst_binary_right_fold (tree t, tree args, tsubst_flags_t complain,
+ tree in_decl)
+{
+ tree pack = tsubst_fold_expr_pack (t, args, complain, in_decl);
+ tree init = tsubst_fold_expr_init (t, args, complain, in_decl);
+
+ int n = TREE_VEC_LENGTH (pack);
+ tree vec = make_tree_vec (n + 1);
+ for (int i = 0; i < n; ++i)
+ TREE_VEC_ELT (vec, i) = TREE_VEC_ELT (pack, i);
+ TREE_VEC_ELT (vec, n) = init;
+
+ return expand_right_fold (t, vec, complain);
+}
+
+
/* Substitute ARGS into T, which is an pack expansion
(i.e. TYPE_PACK_EXPANSION or EXPR_PACK_EXPANSION). Returns a
TREE_VEC with the substituted arguments, a PACK_EXPANSION_* node
@@ -13344,6 +13536,15 @@ tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl)
gcc_assert (!uses_template_parms (t));
return t;
+ case UNARY_LEFT_FOLD_EXPR:
+ return tsubst_unary_left_fold (t, args, complain, in_decl);
+ case UNARY_RIGHT_FOLD_EXPR:
+ return tsubst_unary_right_fold (t, args, complain, in_decl);
+ case BINARY_LEFT_FOLD_EXPR:
+ return tsubst_binary_left_fold (t, args, complain, in_decl);
+ case BINARY_RIGHT_FOLD_EXPR:
+ return tsubst_binary_right_fold (t, args, complain, in_decl);
+
default:
/* We shouldn't get here, but keep going if !ENABLE_CHECKING. */
gcc_checking_assert (false);
@@ -21169,6 +21370,13 @@ type_dependent_expression_p (tree expression)
if (identifier_p (expression) || TREE_CODE (expression) == USING_DECL)
return true;
+ /* A fold expression is type-dependent. */
+ if (TREE_CODE (expression) == UNARY_LEFT_FOLD_EXPR
+ || TREE_CODE (expression) == UNARY_RIGHT_FOLD_EXPR
+ || TREE_CODE (expression) == BINARY_LEFT_FOLD_EXPR
+ || TREE_CODE (expression) == BINARY_RIGHT_FOLD_EXPR)
+ return true;
+
/* Some expression forms are never type-dependent. */
if (TREE_CODE (expression) == PSEUDO_DTOR_EXPR
|| TREE_CODE (expression) == SIZEOF_EXPR