diff options
Diffstat (limited to 'gcc/cp/pt.c')
-rw-r--r-- | gcc/cp/pt.c | 208 |
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 |