This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
RFC: C++ delayed folding merge
- From: Jason Merrill <jason at redhat dot com>
- To: Richard Biener <rguenther at suse dot de>
- Cc: gcc-patches List <gcc-patches at gcc dot gnu dot org>, Marek Polacek <polacek at redhat dot com>
- Date: Mon, 9 Nov 2015 01:30:34 -0500
- Subject: RFC: C++ delayed folding merge
- Authentication-results: sourceware.org; auth=none
I'm planning to merge the C++ delayed folding branch this week, but I
need to get approval of the back end changes (the first patch attached).
Most of these are the introduction of non-folding variants of
convert_to_*, but there are a few others.
One question: The branch changes 'convert' to not fold its result, and
it's not clear to me whether that's part of the expected behavior of a
front end 'convert' function or not.
Also, I'm a bit uncertain about merging this at the end of stage 1,
since it's a large internal change with relatively small user impact; it
just improves handling of constant expression corner cases. I'm
inclined to go ahead with it at this point, but I'm interested in
contrary opinions.
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index ae16cfc..d8c7faf 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -930,8 +930,9 @@ interpret_float (const cpp_token *token, unsigned int flags,
value = build_real (const_type, real);
if (flags & CPP_N_IMAGINARY)
{
- value = build_complex (NULL_TREE, convert (const_type,
- integer_zero_node), value);
+ value = build_complex (NULL_TREE,
+ fold_convert (const_type,
+ integer_zero_node), value);
if (type != const_type)
{
const_type = TREE_TYPE (value);
diff --git a/gcc/convert.c b/gcc/convert.c
index 113c11f..298d1e4 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -34,12 +34,20 @@ along with GCC; see the file COPYING3. If not see
#include "builtins.h"
#include "ubsan.h"
+#define maybe_fold_build1_loc(FOLD_P, LOC, CODE, TYPE, EXPR) \
+ ((FOLD_P) ? fold_build1_loc (LOC, CODE, TYPE, EXPR) \
+ : build1_loc (LOC, CODE, TYPE, EXPR))
+#define maybe_fold_build2_loc(FOLD_P, LOC, CODE, TYPE, EXPR1, EXPR2) \
+ ((FOLD_P) ? fold_build2_loc (LOC, CODE, TYPE, EXPR1, EXPR2) \
+ : build2_loc (LOC, CODE, TYPE, EXPR1, EXPR2))
+
/* Convert EXPR to some pointer or reference type TYPE.
EXPR must be pointer, reference, integer, enumeral, or literal zero;
- in other cases error is called. */
+ in other cases error is called. If FOLD_P is true, try to fold the
+ expression. */
-tree
-convert_to_pointer (tree type, tree expr)
+static tree
+convert_to_pointer_1 (tree type, tree expr, bool fold_p)
{
location_t loc = EXPR_LOCATION (expr);
if (TREE_TYPE (expr) == type)
@@ -56,9 +64,10 @@ convert_to_pointer (tree type, tree expr)
addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (expr)));
if (to_as == from_as)
- return fold_build1_loc (loc, NOP_EXPR, type, expr);
+ return maybe_fold_build1_loc (fold_p, loc, NOP_EXPR, type, expr);
else
- return fold_build1_loc (loc, ADDR_SPACE_CONVERT_EXPR, type, expr);
+ return maybe_fold_build1_loc (fold_p, loc, ADDR_SPACE_CONVERT_EXPR,
+ type, expr);
}
case INTEGER_TYPE:
@@ -72,35 +81,54 @@ convert_to_pointer (tree type, tree expr)
unsigned int pprec = TYPE_PRECISION (type);
unsigned int eprec = TYPE_PRECISION (TREE_TYPE (expr));
- if (eprec != pprec)
- expr = fold_build1_loc (loc, NOP_EXPR,
- lang_hooks.types.type_for_size (pprec, 0),
- expr);
+ if (eprec != pprec)
+ expr
+ = maybe_fold_build1_loc (fold_p, loc, NOP_EXPR,
+ lang_hooks.types.type_for_size (pprec, 0),
+ expr);
}
-
- return fold_build1_loc (loc, CONVERT_EXPR, type, expr);
+ return maybe_fold_build1_loc (fold_p, loc, CONVERT_EXPR, type, expr);
default:
error ("cannot convert to a pointer type");
- return convert_to_pointer (type, integer_zero_node);
+ return convert_to_pointer_1 (type, integer_zero_node, fold_p);
}
}
+/* A wrapper around convert_to_pointer_1 that always folds the
+ expression. */
+
+tree
+convert_to_pointer (tree type, tree expr)
+{
+ return convert_to_pointer_1 (type, expr, true);
+}
+
+/* A wrapper around convert_to_pointer_1 that only folds the
+ expression if it is CONSTANT_CLASS_P. */
+
+tree
+convert_to_pointer_nofold (tree type, tree expr)
+{
+ return convert_to_pointer_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
/* Convert EXPR to some floating-point type TYPE.
EXPR must be float, fixed-point, integer, or enumeral;
- in other cases error is called. */
+ in other cases error is called. If FOLD_P is true, try to fold
+ the expression. */
-tree
-convert_to_real (tree type, tree expr)
+static tree
+convert_to_real_1 (tree type, tree expr, bool fold_p)
{
enum built_in_function fcode = builtin_mathfn_code (expr);
tree itype = TREE_TYPE (expr);
+ location_t loc = EXPR_LOCATION (expr);
if (TREE_CODE (expr) == COMPOUND_EXPR)
{
- tree t = convert_to_real (type, TREE_OPERAND (expr, 1));
+ tree t = convert_to_real_1 (type, TREE_OPERAND (expr, 1), fold_p);
if (t == TREE_OPERAND (expr, 1))
return expr;
return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR, TREE_TYPE (t),
@@ -208,14 +236,13 @@ convert_to_real (tree type, tree expr)
|| TYPE_MODE (newtype) == TYPE_MODE (float_type_node)))
{
tree fn = mathfn_built_in (newtype, fcode);
-
if (fn)
- {
- tree arg = fold (convert_to_real (newtype, arg0));
- expr = build_call_expr (fn, 1, arg);
- if (newtype == type)
- return expr;
- }
+ {
+ tree arg = convert_to_real_1 (newtype, arg0, fold_p);
+ expr = build_call_expr (fn, 1, arg);
+ if (newtype == type)
+ return expr;
+ }
}
}
default:
@@ -234,9 +261,11 @@ convert_to_real (tree type, tree expr)
if (!flag_rounding_math
&& FLOAT_TYPE_P (itype)
&& TYPE_PRECISION (type) < TYPE_PRECISION (itype))
- return build1 (TREE_CODE (expr), type,
- fold (convert_to_real (type,
- TREE_OPERAND (expr, 0))));
+ {
+ tree arg = convert_to_real_1 (type, TREE_OPERAND (expr, 0),
+ fold_p);
+ return build1 (TREE_CODE (expr), type, arg);
+ }
break;
/* Convert (outertype)((innertype0)a+(innertype1)b)
into ((newtype)a+(newtype)b) where newtype
@@ -272,8 +301,10 @@ convert_to_real (tree type, tree expr)
|| newtype == dfloat128_type_node)
{
expr = build2 (TREE_CODE (expr), newtype,
- fold (convert_to_real (newtype, arg0)),
- fold (convert_to_real (newtype, arg1)));
+ convert_to_real_1 (newtype, arg0,
+ fold_p),
+ convert_to_real_1 (newtype, arg1,
+ fold_p));
if (newtype == type)
return expr;
break;
@@ -312,8 +343,10 @@ convert_to_real (tree type, tree expr)
&& !excess_precision_type (newtype))))
{
expr = build2 (TREE_CODE (expr), newtype,
- fold (convert_to_real (newtype, arg0)),
- fold (convert_to_real (newtype, arg1)));
+ convert_to_real_1 (newtype, arg0,
+ fold_p),
+ convert_to_real_1 (newtype, arg1,
+ fold_p));
if (newtype == type)
return expr;
}
@@ -344,30 +377,51 @@ convert_to_real (tree type, tree expr)
case COMPLEX_TYPE:
return convert (type,
- fold_build1 (REALPART_EXPR,
- TREE_TYPE (TREE_TYPE (expr)), expr));
+ maybe_fold_build1_loc (fold_p, loc, REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr));
case POINTER_TYPE:
case REFERENCE_TYPE:
error ("pointer value used where a floating point value was expected");
- return convert_to_real (type, integer_zero_node);
+ return convert_to_real_1 (type, integer_zero_node, fold_p);
default:
error ("aggregate value used where a float was expected");
- return convert_to_real (type, integer_zero_node);
+ return convert_to_real_1 (type, integer_zero_node, fold_p);
}
}
+/* A wrapper around convert_to_real_1 that always folds the
+ expression. */
+
+tree
+convert_to_real (tree type, tree expr)
+{
+ return convert_to_real_1 (type, expr, true);
+}
+
+/* A wrapper around convert_to_real_1 that only folds the
+ expression if it is CONSTANT_CLASS_P. */
+
+tree
+convert_to_real_nofold (tree type, tree expr)
+{
+ return convert_to_real_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
+
/* Convert EXPR to some integer (or enum) type TYPE.
EXPR must be pointer, integer, discrete (enum, char, or bool), float,
fixed-point or vector; in other cases error is called.
+ If DOFOLD is TRUE, we try to simplify newly-created patterns by folding.
+
The result of this is always supposed to be a newly created tree node
not in use in any existing structure. */
-tree
-convert_to_integer (tree type, tree expr)
+static tree
+convert_to_integer_1 (tree type, tree expr, bool dofold)
{
enum tree_code ex_form = TREE_CODE (expr);
tree intype = TREE_TYPE (expr);
@@ -385,7 +439,7 @@ convert_to_integer (tree type, tree expr)
if (ex_form == COMPOUND_EXPR)
{
- tree t = convert_to_integer (type, TREE_OPERAND (expr, 1));
+ tree t = convert_to_integer_1 (type, TREE_OPERAND (expr, 1), dofold);
if (t == TREE_OPERAND (expr, 1))
return expr;
return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR, TREE_TYPE (t),
@@ -479,7 +533,7 @@ convert_to_integer (tree type, tree expr)
break;
CASE_FLT_FN (BUILT_IN_TRUNC):
- return convert_to_integer (type, CALL_EXPR_ARG (s_expr, 0));
+ return convert_to_integer_1 (type, CALL_EXPR_ARG (s_expr, 0), dofold);
default:
break;
@@ -488,7 +542,7 @@ convert_to_integer (tree type, tree expr)
if (fn)
{
tree newexpr = build_call_expr (fn, 1, CALL_EXPR_ARG (s_expr, 0));
- return convert_to_integer (type, newexpr);
+ return convert_to_integer_1 (type, newexpr, dofold);
}
}
@@ -519,7 +573,7 @@ convert_to_integer (tree type, tree expr)
if (fn)
{
tree newexpr = build_call_expr (fn, 1, CALL_EXPR_ARG (s_expr, 0));
- return convert_to_integer (type, newexpr);
+ return convert_to_integer_1 (type, newexpr, dofold);
}
}
@@ -534,6 +588,8 @@ convert_to_integer (tree type, tree expr)
there widen/truncate to the required type. Some targets support the
coexistence of multiple valid pointer sizes, so fetch the one we need
from the type. */
+ if (!dofold)
+ return build1 (CONVERT_EXPR, type, expr);
expr = fold_build1 (CONVERT_EXPR,
lang_hooks.types.type_for_size
(TYPE_PRECISION (intype), 0),
@@ -578,6 +634,8 @@ convert_to_integer (tree type, tree expr)
else
code = NOP_EXPR;
+ if (!dofold)
+ return build1 (code, type, expr);
return fold_build1 (code, type, expr);
}
@@ -784,10 +842,17 @@ convert_to_integer (tree type, tree expr)
if (TYPE_UNSIGNED (typex))
typex = signed_type_for (typex);
}
- return convert (type,
- fold_build2 (ex_form, typex,
- convert (typex, arg0),
- convert (typex, arg1)));
+ /* We should do away with all this once we have a proper
+ type promotion/demotion pass, see PR45397. */
+ if (dofold)
+ return convert (type,
+ fold_build2 (ex_form, typex,
+ convert (typex, arg0),
+ convert (typex, arg1)));
+ arg0 = build1 (CONVERT_EXPR, typex, arg0);
+ arg1 = build1 (CONVERT_EXPR, typex, arg1);
+ expr = build2 (ex_form, typex, arg0, arg1);
+ return build1 (CONVERT_EXPR, type, expr);
}
}
}
@@ -798,6 +863,9 @@ convert_to_integer (tree type, tree expr)
/* This is not correct for ABS_EXPR,
since we must test the sign before truncation. */
{
+ if (!dofold)
+ break;
+
/* Do the arithmetic in type TYPEX,
then convert result to TYPE. */
tree typex = type;
@@ -813,7 +881,7 @@ convert_to_integer (tree type, tree expr)
typex = unsigned_type_for (typex);
return convert (type,
fold_build1 (ex_form, typex,
- convert (typex,
+ convert (typex,
TREE_OPERAND (expr, 0))));
}
@@ -833,13 +901,15 @@ convert_to_integer (tree type, tree expr)
the conditional and never loses. A COND_EXPR may have a throw
as one operand, which then has void type. Just leave void
operands as they are. */
- return fold_build3 (COND_EXPR, type, TREE_OPERAND (expr, 0),
- VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1)))
- ? TREE_OPERAND (expr, 1)
- : convert (type, TREE_OPERAND (expr, 1)),
- VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 2)))
- ? TREE_OPERAND (expr, 2)
- : convert (type, TREE_OPERAND (expr, 2)));
+ if (dofold)
+ return
+ fold_build3 (COND_EXPR, type, TREE_OPERAND (expr, 0),
+ VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1)))
+ ? TREE_OPERAND (expr, 1)
+ : convert (type, TREE_OPERAND (expr, 1)),
+ VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 2)))
+ ? TREE_OPERAND (expr, 2)
+ : convert (type, TREE_OPERAND (expr, 2)));
default:
break;
@@ -860,6 +930,8 @@ convert_to_integer (tree type, tree expr)
expr = build1 (FIX_TRUNC_EXPR, type, expr);
if (check == NULL)
return expr;
+ if (!dofold)
+ return build2 (COMPOUND_EXPR, TREE_TYPE (expr), check, expr);
return fold_build2 (COMPOUND_EXPR, TREE_TYPE (expr), check, expr);
}
else
@@ -869,6 +941,10 @@ convert_to_integer (tree type, tree expr)
return build1 (FIXED_CONVERT_EXPR, type, expr);
case COMPLEX_TYPE:
+ if (!dofold)
+ return convert (type,
+ build1 (REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)), expr));
return convert (type,
fold_build1 (REALPART_EXPR,
TREE_TYPE (TREE_TYPE (expr)), expr));
@@ -889,11 +965,42 @@ convert_to_integer (tree type, tree expr)
}
}
-/* Convert EXPR to the complex type TYPE in the usual ways. */
+/* Convert EXPR to some integer (or enum) type TYPE.
+
+ EXPR must be pointer, integer, discrete (enum, char, or bool), float,
+ fixed-point or vector; in other cases error is called.
+
+ The result of this is always supposed to be a newly created tree node
+ not in use in any existing structure. */
tree
-convert_to_complex (tree type, tree expr)
+convert_to_integer (tree type, tree expr)
+{
+ return convert_to_integer_1 (type, expr, true);
+}
+
+/* Convert EXPR to some integer (or enum) type TYPE.
+
+ EXPR must be pointer, integer, discrete (enum, char, or bool), float,
+ fixed-point or vector; in other cases error is called.
+
+ The result of this is always supposed to be a newly created tree node
+ not in use in any existing structure. The tree node isn't folded,
+ beside EXPR is of constant class. */
+
+tree
+convert_to_integer_nofold (tree type, tree expr)
+{
+ return convert_to_integer_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
+
+/* Convert EXPR to the complex type TYPE in the usual ways. If FOLD_P is
+ true, try to fold the expression. */
+
+static tree
+convert_to_complex_1 (tree type, tree expr, bool fold_p)
{
+ location_t loc = EXPR_LOCATION (expr);
tree subtype = TREE_TYPE (type);
switch (TREE_CODE (TREE_TYPE (expr)))
@@ -914,43 +1021,63 @@ convert_to_complex (tree type, tree expr)
return expr;
else if (TREE_CODE (expr) == COMPOUND_EXPR)
{
- tree t = convert_to_complex (type, TREE_OPERAND (expr, 1));
+ tree t = convert_to_complex_1 (type, TREE_OPERAND (expr, 1),
+ fold_p);
if (t == TREE_OPERAND (expr, 1))
return expr;
return build2_loc (EXPR_LOCATION (expr), COMPOUND_EXPR,
TREE_TYPE (t), TREE_OPERAND (expr, 0), t);
- }
+ }
else if (TREE_CODE (expr) == COMPLEX_EXPR)
- return fold_build2 (COMPLEX_EXPR, type,
- convert (subtype, TREE_OPERAND (expr, 0)),
- convert (subtype, TREE_OPERAND (expr, 1)));
+ return maybe_fold_build2_loc (fold_p, loc, COMPLEX_EXPR, type,
+ convert (subtype,
+ TREE_OPERAND (expr, 0)),
+ convert (subtype,
+ TREE_OPERAND (expr, 1)));
else
{
expr = save_expr (expr);
- return
- fold_build2 (COMPLEX_EXPR, type,
- convert (subtype,
- fold_build1 (REALPART_EXPR,
- TREE_TYPE (TREE_TYPE (expr)),
- expr)),
- convert (subtype,
- fold_build1 (IMAGPART_EXPR,
- TREE_TYPE (TREE_TYPE (expr)),
- expr)));
+ tree realp = maybe_fold_build1_loc (fold_p, loc, REALPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr);
+ tree imagp = maybe_fold_build1_loc (fold_p, loc, IMAGPART_EXPR,
+ TREE_TYPE (TREE_TYPE (expr)),
+ expr);
+ return maybe_fold_build2_loc (fold_p, loc, COMPLEX_EXPR, type,
+ convert (subtype, realp),
+ convert (subtype, imagp));
}
}
case POINTER_TYPE:
case REFERENCE_TYPE:
error ("pointer value used where a complex was expected");
- return convert_to_complex (type, integer_zero_node);
+ return convert_to_complex_1 (type, integer_zero_node, fold_p);
default:
error ("aggregate value used where a complex was expected");
- return convert_to_complex (type, integer_zero_node);
+ return convert_to_complex_1 (type, integer_zero_node, fold_p);
}
}
+/* A wrapper around convert_to_complex_1 that always folds the
+ expression. */
+
+tree
+convert_to_complex (tree type, tree expr)
+{
+ return convert_to_complex_1 (type, expr, true);
+}
+
+/* A wrapper around convert_to_complex_1 that only folds the
+ expression if it is CONSTANT_CLASS_P. */
+
+tree
+convert_to_complex_nofold (tree type, tree expr)
+{
+ return convert_to_complex_1 (type, expr, CONSTANT_CLASS_P (expr));
+}
+
/* Convert EXPR to the vector type TYPE in the usual ways. */
tree
diff --git a/gcc/convert.h b/gcc/convert.h
index f2e4a65..7cc3168 100644
--- a/gcc/convert.h
+++ b/gcc/convert.h
@@ -21,10 +21,14 @@ along with GCC; see the file COPYING3. If not see
#define GCC_CONVERT_H
extern tree convert_to_integer (tree, tree);
+extern tree convert_to_integer_nofold (tree, tree);
extern tree convert_to_pointer (tree, tree);
+extern tree convert_to_pointer_nofold (tree, tree);
extern tree convert_to_real (tree, tree);
+extern tree convert_to_real_nofold (tree, tree);
extern tree convert_to_fixed (tree, tree);
extern tree convert_to_complex (tree, tree);
+extern tree convert_to_complex_nofold (tree, tree);
extern tree convert_to_vector (tree, tree);
#endif /* GCC_CONVERT_H */
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 0b7d143..536989b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4747,7 +4747,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
tree cmp_type = build_same_sized_truth_vector_type (arg1_type);
arg1 = build2 (NE_EXPR, cmp_type, arg1, build_zero_cst (arg1_type));
}
- return fold_build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
+ return build3_loc (loc, VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
}
/* [expr.cond]
@@ -5151,9 +5151,6 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
valid_operands:
result = build3_loc (loc, COND_EXPR, result_type, arg1, arg2, arg3);
- if (!cp_unevaluated_operand)
- /* Avoid folding within decltype (c++/42013) and noexcept. */
- result = fold_if_not_in_template (result);
/* We can't use result_type below, as fold might have returned a
throw_expr. */
@@ -5689,8 +5686,8 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
decaying an enumerator to its value. */
if (complain & tf_warning)
warn_logical_operator (loc, code, boolean_type_node,
- code_orig_arg1, arg1,
- code_orig_arg2, arg2);
+ code_orig_arg1, fold (arg1),
+ code_orig_arg2, fold (arg2));
arg2 = convert_like (conv, arg2, complain);
}
@@ -5728,7 +5725,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
case TRUTH_OR_EXPR:
if (complain & tf_warning)
warn_logical_operator (loc, code, boolean_type_node,
- code_orig_arg1, arg1, code_orig_arg2, arg2);
+ code_orig_arg1, fold (arg1), code_orig_arg2, fold (arg2));
/* Fall through. */
case GT_EXPR:
case LT_EXPR:
@@ -5739,9 +5736,10 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
if ((complain & tf_warning)
&& ((code_orig_arg1 == BOOLEAN_TYPE)
^ (code_orig_arg2 == BOOLEAN_TYPE)))
- maybe_warn_bool_compare (loc, code, arg1, arg2);
+ maybe_warn_bool_compare (loc, code, fold (arg1),
+ fold (arg2));
if (complain & tf_warning && warn_tautological_compare)
- warn_tautological_cmp (loc, code, arg1, arg2);
+ warn_tautological_cmp (loc, code, fold (arg1), fold (arg2));
/* Fall through. */
case PLUS_EXPR:
case MINUS_EXPR:
@@ -6495,7 +6493,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
imag = perform_implicit_conversion (TREE_TYPE (totype),
imag, complain);
expr = build2 (COMPLEX_EXPR, totype, real, imag);
- return fold_if_not_in_template (expr);
+ return expr;
}
expr = reshape_init (totype, expr, complain);
expr = get_target_expr_sfinae (digest_init (totype, expr, complain),
@@ -6736,7 +6734,7 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
"implicit conversion from %qT to %qT when passing "
"argument to function",
arg_type, double_type_node);
- arg = convert_to_real (double_type_node, arg);
+ arg = convert_to_real_nofold (double_type_node, arg);
}
else if (NULLPTR_TYPE_P (arg_type))
arg = null_pointer_node;
@@ -6981,7 +6979,7 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
bitfield_type = is_bitfield_expr_with_lowered_type (val);
if (bitfield_type
&& TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type))
- val = convert_to_integer (TYPE_MAIN_VARIANT (bitfield_type), val);
+ val = convert_to_integer_nofold (TYPE_MAIN_VARIANT (bitfield_type), val);
if (val == error_mark_node)
;
@@ -7501,7 +7499,19 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
gcc_assert (j <= nargs);
nargs = j;
- check_function_arguments (TREE_TYPE (fn), nargs, argarray);
+ /* Avoid to do argument-transformation, if warnings for format, and for
+ nonnull are disabled. Just in case that at least one of them is active
+ the check_function_arguments function might warn about something. */
+
+ if (warn_nonnull || warn_format || warn_suggest_attribute_format)
+ {
+ tree *fargs = (!nargs ? argarray
+ : (tree *) alloca (nargs * sizeof (tree)));
+ for (j = 0; j < nargs; j++)
+ fargs[j] = maybe_constant_value (argarray[j]);
+
+ check_function_arguments (TREE_TYPE (fn), nargs, fargs);
+ }
/* Avoid actually calling copy constructors and copy assignment operators,
if possible. */
@@ -7692,7 +7702,6 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
tsubst_flags_t complain)
{
tree fndecl;
- int optimize_sav;
/* Remember roughly where this call is. */
location_t loc = EXPR_LOC_OR_LOC (fn, input_location);
@@ -7704,9 +7713,18 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
/* Check that arguments to builtin functions match the expectations. */
if (fndecl
&& DECL_BUILT_IN (fndecl)
- && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
- && !check_builtin_function_arguments (fndecl, nargs, argarray))
- return error_mark_node;
+ && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+ {
+ int i;
+
+ /* We need to take care that values to BUILT_IN_NORMAL
+ are reduced. */
+ for (i = 0; i < nargs; i++)
+ argarray[i] = maybe_constant_value (argarray[i]);
+
+ if (!check_builtin_function_arguments (fndecl, nargs, argarray))
+ return error_mark_node;
+ }
/* If it is a built-in array notation function, then the return type of
the function is the element type of the array passed in as array
@@ -7740,17 +7758,6 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
}
}
- /* Some built-in function calls will be evaluated at compile-time in
- fold (). Set optimize to 1 when folding __builtin_constant_p inside
- a constexpr function so that fold_builtin_1 doesn't fold it to 0. */
- optimize_sav = optimize;
- if (!optimize && fndecl && DECL_IS_BUILTIN_CONSTANT_P (fndecl)
- && current_function_decl
- && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
- optimize = 1;
- fn = fold_if_not_in_template (fn);
- optimize = optimize_sav;
-
if (VOID_TYPE_P (TREE_TYPE (fn)))
return fn;
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index b123932..b5cf996 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -423,7 +423,7 @@ build_base_path (enum tree_code code,
t = TREE_TYPE (TYPE_VFIELD (current_class_type));
t = build_pointer_type (t);
- v_offset = convert (t, current_vtt_parm);
+ v_offset = fold_convert (t, current_vtt_parm);
v_offset = cp_build_indirect_ref (v_offset, RO_NULL, complain);
}
else
@@ -556,8 +556,6 @@ build_simple_base_path (tree expr, tree binfo)
expr = build3 (COMPONENT_REF,
cp_build_qualified_type (type, type_quals),
expr, field, NULL_TREE);
- expr = fold_if_not_in_template (expr);
-
/* Mark the expression const or volatile, as appropriate.
Even though we've dealt with the type above, we still have
to mark the expression itself. */
@@ -1849,9 +1847,9 @@ determine_primary_bases (tree t)
another hierarchy. As we're about to use it as a
primary base, make sure the offsets match. */
delta = size_diffop_loc (input_location,
- convert (ssizetype,
+ fold_convert (ssizetype,
BINFO_OFFSET (base_binfo)),
- convert (ssizetype,
+ fold_convert (ssizetype,
BINFO_OFFSET (this_primary)));
propagate_binfo_offsets (this_primary, delta);
@@ -1913,7 +1911,7 @@ determine_primary_bases (tree t)
another hierarchy. As we're about to use it as a primary
base, make sure the offsets match. */
delta = size_diffop_loc (input_location, ssize_int (0),
- convert (ssizetype, BINFO_OFFSET (primary)));
+ fold_convert (ssizetype, BINFO_OFFSET (primary)));
propagate_binfo_offsets (primary, delta);
}
@@ -2637,7 +2635,7 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
if (virtual_offset
|| (thunk_binfo && !BINFO_OFFSET_ZEROP (thunk_binfo)))
{
- tree offset = convert (ssizetype, BINFO_OFFSET (thunk_binfo));
+ tree offset = fold_convert (ssizetype, BINFO_OFFSET (thunk_binfo));
if (virtual_offset)
{
@@ -2645,7 +2643,7 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
offset to be from there. */
offset =
size_diffop (offset,
- convert (ssizetype,
+ fold_convert (ssizetype,
BINFO_OFFSET (virtual_offset)));
}
if (fixed_offset)
@@ -2734,8 +2732,8 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
/* The `this' pointer needs to be adjusted from the declaration to
the nearest virtual base. */
delta = size_diffop_loc (input_location,
- convert (ssizetype, BINFO_OFFSET (virtual_base)),
- convert (ssizetype, BINFO_OFFSET (first_defn)));
+ fold_convert (ssizetype, BINFO_OFFSET (virtual_base)),
+ fold_convert (ssizetype, BINFO_OFFSET (first_defn)));
else if (lost)
/* If the nearest definition is in a lost primary, we don't need an
entry in our vtable. Except possibly in a constructor vtable,
@@ -2747,9 +2745,9 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
BINFO to pointing at the base where the final overrider
appears. */
delta = size_diffop_loc (input_location,
- convert (ssizetype,
+ fold_convert (ssizetype,
BINFO_OFFSET (TREE_VALUE (overrider))),
- convert (ssizetype, BINFO_OFFSET (binfo)));
+ fold_convert (ssizetype, BINFO_OFFSET (binfo)));
modify_vtable_entry (t, binfo, overrider_fn, delta, virtuals);
@@ -3471,7 +3469,7 @@ check_bitfield_decl (tree field)
if (w != error_mark_node)
{
- DECL_SIZE (field) = convert (bitsizetype, w);
+ DECL_SIZE (field) = fold_convert (bitsizetype, w);
DECL_BIT_FIELD (field) = 1;
return true;
}
@@ -4316,8 +4314,8 @@ layout_nonempty_base_or_field (record_layout_info rli,
OFFSET. */
propagate_binfo_offsets (binfo,
size_diffop_loc (input_location,
- convert (ssizetype, offset),
- convert (ssizetype,
+ fold_convert (ssizetype, offset),
+ fold_convert (ssizetype,
BINFO_OFFSET (binfo))));
}
@@ -4364,7 +4362,7 @@ layout_empty_base (record_layout_info rli, tree binfo,
/* That didn't work. Now, we move forward from the next
available spot in the class. */
atend = true;
- propagate_binfo_offsets (binfo, convert (ssizetype, eoc));
+ propagate_binfo_offsets (binfo, fold_convert (ssizetype, eoc));
while (1)
{
if (!layout_conflict_p (binfo,
@@ -5978,9 +5976,9 @@ propagate_binfo_offsets (tree binfo, tree offset)
/* Update BINFO's offset. */
BINFO_OFFSET (binfo)
- = convert (sizetype,
+ = fold_convert (sizetype,
size_binop (PLUS_EXPR,
- convert (ssizetype, BINFO_OFFSET (binfo)),
+ fold_convert (ssizetype, BINFO_OFFSET (binfo)),
offset));
/* Find the primary base class. */
@@ -6185,7 +6183,7 @@ include_empty_classes (record_layout_info rli)
= size_binop (PLUS_EXPR,
rli->bitpos,
size_binop (MULT_EXPR,
- convert (bitsizetype,
+ fold_convert (bitsizetype,
size_binop (MINUS_EXPR,
eoc, rli_size)),
bitsize_int (BITS_PER_UNIT)));
@@ -6459,7 +6457,7 @@ layout_class_type (tree t, tree *virtuals_p)
eoc = end_of_class (t, /*include_virtuals_p=*/0);
TYPE_SIZE_UNIT (base_t)
= size_binop (MAX_EXPR,
- convert (sizetype,
+ fold_convert (sizetype,
size_binop (CEIL_DIV_EXPR,
rli_size_so_far (rli),
bitsize_int (BITS_PER_UNIT))),
@@ -6468,7 +6466,7 @@ layout_class_type (tree t, tree *virtuals_p)
= size_binop (MAX_EXPR,
rli_size_so_far (rli),
size_binop (MULT_EXPR,
- convert (bitsizetype, eoc),
+ fold_convert (bitsizetype, eoc),
bitsize_int (BITS_PER_UNIT)));
TYPE_ALIGN (base_t) = rli->record_align;
TYPE_USER_ALIGN (base_t) = TYPE_USER_ALIGN (t);
@@ -9304,7 +9302,7 @@ build_vbase_offset_vtbl_entries (tree binfo, vtbl_init_data* vid)
/* Figure out where we can find this vbase offset. */
delta = size_binop (MULT_EXPR,
vid->index,
- convert (ssizetype,
+ fold_convert (ssizetype,
TYPE_SIZE_UNIT (vtable_entry_type)));
if (vid->primary_vtbl_p)
BINFO_VPTR_FIELD (b) = delta;
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 51fae5a..eefe322 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1037,6 +1037,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
force_folding_builtin_constant_p = true;
new_call = fold_build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
CALL_EXPR_FN (t), nargs, args);
+ /* Fold away the NOP_EXPR from fold_builtin_n. */
+ new_call = fold (new_call);
force_folding_builtin_constant_p = save_ffbcp;
VERIFY_CONSTANT (new_call);
return new_call;
@@ -1277,6 +1279,15 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
ctx->values->put (new_ctx.object, ctor);
ctx = &new_ctx;
}
+ else if (DECL_BY_REFERENCE (DECL_RESULT (fun))
+ && TREE_CODE (t) != AGGR_INIT_EXPR)
+ {
+ /* convert_to_void stripped our AGGR_INIT_EXPR, in which case we don't
+ care about a constant value. */
+ gcc_assert (ctx->quiet && !ctx->object);
+ *non_constant_p = true;
+ return t;
+ }
bool non_constant_args = false;
cxx_bind_parameters_in_call (ctx, t, &new_call,
@@ -2542,6 +2553,17 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
tree orig_op0 = TREE_OPERAND (t, 0);
bool empty_base = false;
+ /* We can handle a MEM_REF like an INDIRECT_REF, if MEM_REF's second
+ operand is an integer-zero. Otherwise reject the MEM_REF for now. */
+
+ if (TREE_CODE (t) == MEM_REF
+ && (!TREE_OPERAND (t, 1) || !integer_zerop (TREE_OPERAND (t, 1))))
+ {
+ gcc_assert (ctx->quiet);
+ *non_constant_p = true;
+ return t;
+ }
+
/* First try to simplify it directly. */
tree r = cxx_fold_indirect_ref (EXPR_LOCATION (t), TREE_TYPE (t), orig_op0,
&empty_base);
@@ -3075,6 +3097,8 @@ cxx_eval_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CODE (op00) != ADDR_EXPR)
return NULL_TREE;
+ op01 = cxx_eval_constant_expression (ctx, op01, lval,
+ non_constant_p, overflow_p);
op00 = TREE_OPERAND (op00, 0);
/* &A[i] p+ j => &A[i + j] */
@@ -3112,6 +3136,26 @@ cxx_eval_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
return NULL_TREE;
}
+/* Reduce a SIZEOF_EXPR to its value. */
+
+tree
+fold_sizeof_expr (tree t)
+{
+ tree r;
+ 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;
+ return r;
+}
+
/* 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 */
@@ -3335,6 +3379,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
/* 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 MEM_REF:
case INDIRECT_REF:
r = cxx_eval_indirect_ref (ctx, t, lval,
non_constant_p, overflow_p);
@@ -3372,17 +3417,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
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;
+ r = fold_sizeof_expr (t);
VERIFY_CONSTANT (r);
break;
@@ -3540,8 +3575,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case CONVERT_EXPR:
case VIEW_CONVERT_EXPR:
case NOP_EXPR:
+ case UNARY_PLUS_EXPR:
{
+ enum tree_code tcode = TREE_CODE (t);
tree oldop = TREE_OPERAND (t, 0);
+
tree op = cxx_eval_constant_expression (ctx, oldop,
lval,
non_constant_p, overflow_p);
@@ -3561,11 +3599,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
*non_constant_p = true;
return t;
}
- if (op == oldop)
+ if (op == oldop && tcode != UNARY_PLUS_EXPR)
/* We didn't fold at the top so we could check for ptr-int
conversion. */
return fold (t);
- r = fold_build1 (TREE_CODE (t), type, op);
+ if (tcode == UNARY_PLUS_EXPR)
+ r = fold_convert (TREE_TYPE (t), op);
+ else
+ r = fold_build1 (tcode, type, op);
/* Conversion of an out-of-range value has implementation-defined
behavior; the language considers it different from arithmetic
overflow, which is undefined. */
@@ -3833,12 +3874,86 @@ cxx_constant_value (tree t, tree decl)
return cxx_eval_outermost_constant_expr (t, false, true, decl);
}
+/* Helper routine for fold_simple function. Either return simplified
+ expression T, otherwise NULL_TREE.
+ In contrast to cp_fully_fold, and to maybe_constant_value, we try to fold
+ even if we are within template-declaration. So be careful on call, as in
+ such case types can be undefined. */
+
+static tree
+fold_simple_1 (tree t)
+{
+ tree op1;
+ enum tree_code code = TREE_CODE (t);
+
+ switch (code)
+ {
+ case INTEGER_CST:
+ case REAL_CST:
+ case VECTOR_CST:
+ case FIXED_CST:
+ case COMPLEX_CST:
+ return t;
+
+ case SIZEOF_EXPR:
+ return fold_sizeof_expr (t);
+
+ case ABS_EXPR:
+ case CONJ_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case NEGATE_EXPR:
+ case BIT_NOT_EXPR:
+ case TRUTH_NOT_EXPR:
+ case NOP_EXPR:
+ case VIEW_CONVERT_EXPR:
+ case CONVERT_EXPR:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case FIXED_CONVERT_EXPR:
+ case ADDR_SPACE_CONVERT_EXPR:
+
+ op1 = TREE_OPERAND (t, 0);
+
+ t = const_unop (code, TREE_TYPE (t), op1);
+ if (!t)
+ return NULL_TREE;
+
+ if (CONVERT_EXPR_CODE_P (code)
+ && TREE_OVERFLOW_P (t) && !TREE_OVERFLOW_P (op1))
+ TREE_OVERFLOW (t) = false;
+ return t;
+
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* If T is a simple constant expression, returns its simplified value.
+ Otherwise returns T. In contrast to maybe_constant_value do we
+ simplify only few operations on constant-expressions, and we don't
+ try to simplify constexpressions. */
+
+tree
+fold_simple (tree t)
+{
+ tree r = NULL_TREE;
+ if (processing_template_decl)
+ return t;
+
+ r = fold_simple_1 (t);
+ if (!r)
+ r = t;
+
+ return r;
+}
+
/* 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 decl)
+static tree
+maybe_constant_value_1 (tree t, tree decl)
{
tree r;
@@ -3864,6 +3979,56 @@ maybe_constant_value (tree t, tree decl)
return r;
}
+/* 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 decl)
+{
+ tree ret;
+ hash_map<tree, tree> *ctx = (scope_chain ? scope_chain->fold_map : NULL);
+ hash_map<tree, tree> *cv = (scope_chain ? scope_chain->cv_map : NULL);
+
+ /* If current scope has a hash_map, but it was for different CFUN,
+ then destroy hash_map to avoid issues with ggc_collect. */
+ if ((cv || ctx) && scope_chain->act_cfun != cfun)
+ {
+ if (ctx)
+ delete ctx;
+ if (cv)
+ delete cv;
+ ctx = NULL;
+ scope_chain->act_cfun = NULL;
+ scope_chain->fold_map = NULL;
+ scope_chain->cv_map = NULL;
+ }
+ if (cv && scope_chain && cfun)
+ {
+ cv = scope_chain->cv_map = new hash_map <tree, tree>;
+ scope_chain->act_cfun = cfun;
+ }
+
+ if (cv)
+ {
+ tree *slot = cv->get (t);
+ if (slot && *slot)
+ return *slot;
+ }
+
+ ret = maybe_constant_value_1 (t, decl);
+
+ if (cv)
+ {
+ /* We don't need to cache RET, as it is a
+ constant-value if it differs. */
+ tree *slot = &cv->get_or_insert (t);
+ *slot = ret;
+ }
+
+ return ret;
+}
+
/* Like maybe_constant_value but first fully instantiate the argument.
Note: this is equivalent to instantiate_non_dependent_expr_sfinae
@@ -3929,6 +4094,8 @@ fold_non_dependent_expr (tree t)
tree
maybe_constant_init (tree t, tree decl)
{
+ if (!t)
+ return t;
if (TREE_CODE (t) == EXPR_STMT)
t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == CONVERT_EXPR
@@ -4039,6 +4206,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
/* We can see a FIELD_DECL in a pointer-to-member expression. */
case FIELD_DECL:
case PARM_DECL:
+ case RESULT_DECL:
case USING_DECL:
case USING_STMT:
case PLACEHOLDER_EXPR:
@@ -4627,6 +4795,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
/* We can see these in statement-expressions. */
return true;
+ case EMPTY_CLASS_EXPR:
+ return false;
+
default:
if (objc_is_property_ref (t))
return false;
diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c
index 9fd348c..e967c72 100644
--- a/gcc/cp/cp-array-notation.c
+++ b/gcc/cp/cp-array-notation.c
@@ -1382,7 +1382,12 @@ build_array_notation_ref (location_t loc, tree array, tree start, tree length,
if (!stride)
stride = build_one_cst (ptrdiff_type_node);
-
+
+ stride = maybe_constant_value (stride);
+ length = maybe_constant_value (length);
+ if (start)
+ start = maybe_constant_value (start);
+
/* When dealing with templates, triplet type-checking will be done in pt.c
after type substitution. */
if (processing_template_decl
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index e4b50e5..88baa40 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -41,7 +41,9 @@ along with GCC; see the file COPYING3. If not see
/* Forward declarations. */
static tree cp_genericize_r (tree *, int *, void *);
+static tree cp_fold_r (tree *, int *, void *);
static void cp_genericize_tree (tree*);
+static tree cp_fold (tree, hash_map<tree, tree> *);
/* Local declarations. */
@@ -181,13 +183,13 @@ genericize_eh_spec_block (tree *stmt_p)
/* Genericize an IF_STMT by turning it into a COND_EXPR. */
static void
-genericize_if_stmt (tree *stmt_p)
+genericize_if_stmt (tree *stmt_p, hash_map<tree, tree> *fold_hash)
{
tree stmt, cond, then_, else_;
location_t locus = EXPR_LOCATION (*stmt_p);
stmt = *stmt_p;
- cond = IF_COND (stmt);
+ cond = cp_fold (IF_COND (stmt), fold_hash);
then_ = THEN_CLAUSE (stmt);
else_ = ELSE_CLAUSE (stmt);
@@ -916,9 +918,76 @@ struct cp_genericize_data
vec<tree> bind_expr_stack;
struct cp_genericize_omp_taskreg *omp_ctx;
tree try_block;
+ hash_map<tree, tree> *fold_hash;
bool no_sanitize_p;
};
+/* Perform any pre-gimplification folding of C++ front end trees to
+ GENERIC.
+ Note: The folding of none-omp cases is something to move into
+ the middle-end. As for now we have most foldings only on GENERIC
+ in fold-const, we need to perform this before transformation to
+ GIMPLE-form. */
+
+static tree
+cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
+{
+ tree stmt;
+ struct cp_genericize_data *wtd = (struct cp_genericize_data *) data;
+ enum tree_code code;
+
+ *stmt_p = stmt = cp_fold (*stmt_p, wtd->fold_hash);
+
+ code = TREE_CODE (stmt);
+ if (code == OMP_FOR || code == OMP_SIMD || code == OMP_DISTRIBUTE
+ || code == OMP_TASKLOOP || code == CILK_FOR || code == CILK_SIMD)
+ {
+ tree x;
+ int i, n;
+
+ cp_walk_tree (&OMP_FOR_BODY (stmt), cp_fold_r, data, NULL);
+ cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_fold_r, data, NULL);
+ cp_walk_tree (&OMP_FOR_INIT (stmt), cp_fold_r, data, NULL);
+ x = OMP_FOR_COND (stmt);
+ if (x && TREE_CODE_CLASS (TREE_CODE (x)) == tcc_comparison)
+ {
+ cp_walk_tree (&TREE_OPERAND (x, 0), cp_fold_r, data, NULL);
+ cp_walk_tree (&TREE_OPERAND (x, 1), cp_fold_r, data, NULL);
+ }
+ else if (x && TREE_CODE (x) == TREE_VEC)
+ {
+ n = TREE_VEC_LENGTH (x);
+ for (i = 0; i < n; i++)
+ {
+ tree o = TREE_VEC_ELT (x, i);
+ if (o && TREE_CODE_CLASS (TREE_CODE (o)) == tcc_comparison)
+ cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL);
+ }
+ }
+ x = OMP_FOR_INCR (stmt);
+ if (x && TREE_CODE (x) == TREE_VEC)
+ {
+ n = TREE_VEC_LENGTH (x);
+ for (i = 0; i < n; i++)
+ {
+ tree o = TREE_VEC_ELT (x, i);
+ if (o && TREE_CODE (o) == MODIFY_EXPR)
+ o = TREE_OPERAND (o, 1);
+ if (o && (TREE_CODE (o) == PLUS_EXPR || TREE_CODE (o) == MINUS_EXPR
+ || TREE_CODE (o) == POINTER_PLUS_EXPR))
+ {
+ cp_walk_tree (&TREE_OPERAND (o, 0), cp_fold_r, data, NULL);
+ cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL);
+ }
+ }
+ }
+ cp_walk_tree (&OMP_FOR_PRE_BODY (stmt), cp_fold_r, data, NULL);
+ *walk_subtrees = 0;
+ }
+
+ return NULL;
+}
+
/* Perform any pre-gimplification lowering of C++ front end trees to
GENERIC. */
@@ -978,7 +1047,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
if (__builtin_expect (wtd->omp_ctx != NULL, 0)
&& omp_var_to_track (TREE_OPERAND (stmt, 0)))
omp_cxx_notice_variable (wtd->omp_ctx, TREE_OPERAND (stmt, 0));
- *stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
+ *stmt_p = fold_convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
*walk_subtrees = 0;
}
else if (TREE_CODE (stmt) == RETURN_EXPR
@@ -1058,7 +1127,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
else if (TREE_CODE (stmt) == IF_STMT)
{
- genericize_if_stmt (stmt_p);
+ genericize_if_stmt (stmt_p, wtd->fold_hash);
/* *stmt_p has changed, tail recurse to handle it again. */
return cp_genericize_r (stmt_p, walk_subtrees, data);
}
@@ -1307,6 +1376,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
SIZEOF_EXPR, false);
if (*stmt_p == error_mark_node)
*stmt_p = size_one_node;
+ *stmt_p = cp_fold (*stmt_p, wtd->fold_hash);
return NULL;
}
else if ((flag_sanitize
@@ -1349,12 +1419,15 @@ cp_genericize_tree (tree* t_p)
{
struct cp_genericize_data wtd;
+ wtd.fold_hash = new hash_map<tree, tree>;
wtd.p_set = new hash_set<tree>;
wtd.bind_expr_stack.create (0);
wtd.omp_ctx = NULL;
wtd.try_block = NULL_TREE;
wtd.no_sanitize_p = false;
cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL);
+ cp_walk_tree (t_p, cp_fold_r, &wtd, NULL);
+ delete wtd.fold_hash;
delete wtd.p_set;
wtd.bind_expr_stack.release ();
if (flag_sanitize & SANITIZE_VPTR)
@@ -1782,3 +1855,472 @@ cxx_omp_disregard_value_expr (tree decl, bool shared)
&& DECL_LANG_SPECIFIC (decl)
&& DECL_OMP_PRIVATIZED_MEMBER (decl);
}
+
+/* Callback for walk_tree, looking for LABEL_EXPR. Return *TP if it is
+ a LABEL_EXPR; otherwise return NULL_TREE. Do not check the subtrees
+ of GOTO_EXPR. */
+
+static tree
+contains_label_1 (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+{
+ switch (TREE_CODE (*tp))
+ {
+ case LABEL_EXPR:
+ return *tp;
+
+ case GOTO_EXPR:
+ *walk_subtrees = 0;
+
+ /* ... fall through ... */
+
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* Return whether the sub-tree ST contains a label which is accessible from
+ outside the sub-tree. */
+
+static bool
+contains_label_p (tree st)
+{
+ return
+ walk_tree_without_duplicates (&st, contains_label_1 , NULL) != NULL_TREE;
+}
+
+/* Perform folding on expression X. */
+
+tree
+cp_fully_fold (tree x)
+{
+ hash_map<tree, tree> *ctx = (scope_chain ? scope_chain->fold_map : NULL);
+ hash_map<tree, tree> *cv = (scope_chain ? scope_chain->cv_map : NULL);
+
+ /* If current scope has a hash_map, but it was for different CFUN,
+ then destroy hash_map to avoid issues with ggc_collect. */
+ if ((cv || ctx) && scope_chain->act_cfun != cfun)
+ {
+ if (ctx)
+ delete ctx;
+ if (cv)
+ delete cv;
+ ctx = NULL;
+ scope_chain->act_cfun = NULL;
+ scope_chain->fold_map = NULL;
+ scope_chain->cv_map = NULL;
+ }
+
+ /* If there is no hash_map, but there is a scope, and a set CFUN,
+ then create the hash_map for scope. */
+ if (!ctx && scope_chain && cfun)
+ {
+ ctx = scope_chain->fold_map = new hash_map <tree, tree>;
+ scope_chain->act_cfun = cfun;
+ }
+ /* Otherwise if there is no hash_map, use for folding temporary
+ hash_map. */
+ else if (!ctx)
+ {
+ hash_map<tree, tree> fold_hash;
+ return cp_fold (x, &fold_hash);
+ }
+
+ return cp_fold (x, ctx);
+}
+
+/* This function tries to fold given expression X in GENERIC-form.
+ For performance-reason, and for avoiding endless-recursion the
+ function uses given tree-hash FOLD_HASH.
+ If FOLD_HASH is 0, or we are processing within template-declaration,
+ or X is no valid expression, or has no valid type, we don't fold at all.
+ For performance-reason we don't hash on expressions representing a
+ declaration, or being of constant-class.
+ Function returns X, or its folded variant. */
+
+static tree
+cp_fold (tree x, hash_map<tree, tree> *fold_hash)
+{
+ tree *slot, op0, op1, op2, op3;
+ tree org_x = x, r = NULL_TREE;
+ enum tree_code code;
+ location_t loc;
+
+ if (!x || x == error_mark_node)
+ return x;
+
+ if (!fold_hash
+ || processing_template_decl
+ || (EXPR_P (x) && !TREE_TYPE (x)))
+ return x;
+
+ /* Don't even try to hash on DECLs or constants. */
+ if (DECL_P (x) || CONSTANT_CLASS_P (x))
+ return x;
+
+ slot = fold_hash->get (x);
+ if (slot && *slot)
+ return *slot;
+
+ code = TREE_CODE (x);
+ switch (code)
+ {
+ case SIZEOF_EXPR:
+ x = fold_sizeof_expr (x);
+ break;
+
+ case VIEW_CONVERT_EXPR:
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+
+ if (VOID_TYPE_P (TREE_TYPE (x)))
+ return x;
+
+ if (!TREE_OPERAND (x, 0)
+ || TREE_CODE (TREE_OPERAND (x, 0)) == NON_LVALUE_EXPR)
+ return x;
+
+ loc = EXPR_LOCATION (x);
+ op0 = TREE_OPERAND (x, 0);
+
+ if (TREE_CODE (x) == NOP_EXPR
+ && TREE_OVERFLOW_P (op0)
+ && TREE_TYPE (x) == TREE_TYPE (op0))
+ return x;
+
+ op0 = cp_fold (op0, fold_hash);
+
+ if (op0 != TREE_OPERAND (x, 0))
+ x = build1_loc (loc, code, TREE_TYPE (x), op0);
+
+ x = fold (x);
+
+ /* Conversion of an out-of-range value has implementation-defined
+ behavior; the language considers it different from arithmetic
+ overflow, which is undefined. */
+ if (TREE_CODE (op0) == INTEGER_CST
+ && TREE_OVERFLOW_P (x) && !TREE_OVERFLOW_P (op0))
+ TREE_OVERFLOW (x) = false;
+
+ break;
+
+ case ALIGNOF_EXPR:
+ case SAVE_EXPR:
+ case ADDR_EXPR:
+ 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:
+ case UNARY_PLUS_EXPR:
+ case CLEANUP_POINT_EXPR:
+ case INDIRECT_REF:
+ /* case NON_LVALUE_EXPR: */
+ case RETURN_EXPR:
+ case EXPR_STMT:
+ case STMT_EXPR:
+ case GOTO_EXPR:
+ case EXIT_EXPR:
+ case LOOP_EXPR:
+
+ loc = EXPR_LOCATION (x);
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+ if (op0 != TREE_OPERAND (x, 0))
+ x = build1_loc (loc, code, TREE_TYPE (x), op0);
+
+ x = fold (x);
+
+ gcc_assert (TREE_CODE (x) != COND_EXPR
+ || !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))));
+ break;
+
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case INIT_EXPR:
+
+ loc = EXPR_LOCATION (x);
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+ op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+
+ if (TREE_OPERAND (x, 0) != op0 || TREE_OPERAND (x, 1) != op1)
+ x = build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+
+ break;
+
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case COMPOUND_EXPR:
+ 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_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_ORIF_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:
+ case MODIFY_EXPR:
+
+ loc = EXPR_LOCATION (x);
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+ op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+ if ((code == COMPOUND_EXPR || code == MODIFY_EXPR)
+ && ((op1 && TREE_SIDE_EFFECTS (op1))
+ || (op0 && TREE_SIDE_EFFECTS (op0))))
+ break;
+ if (TREE_CODE (x) == COMPOUND_EXPR && !op0)
+ op0 = build_empty_stmt (loc);
+
+ if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1))
+ x = build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+
+ x = fold (x);
+
+ if (TREE_CODE (x) == COMPOUND_EXPR && TREE_OPERAND (x, 0) == NULL_TREE
+ && TREE_OPERAND (x, 1))
+ return TREE_OPERAND (x, 1);
+ break;
+
+ case VEC_COND_EXPR:
+ case COND_EXPR:
+
+ loc = EXPR_LOCATION (x);
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+ if (TREE_SIDE_EFFECTS (op0))
+ break;
+
+ op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+ op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+
+ if (TREE_CODE (op0) == INTEGER_CST)
+ {
+ tree un;
+
+ if (integer_zerop (op0))
+ {
+ un = op1;
+ r = op2;
+ }
+ else
+ {
+ un = op2;
+ r = op1;
+ }
+
+ if ((!TREE_SIDE_EFFECTS (un) || !contains_label_p (un))
+ && (! VOID_TYPE_P (TREE_TYPE (r)) || VOID_TYPE_P (x)))
+ {
+ if (CAN_HAVE_LOCATION_P (r)
+ && EXPR_LOCATION (r) != loc
+ && !(TREE_CODE (r) == SAVE_EXPR
+ || TREE_CODE (r) == TARGET_EXPR
+ || TREE_CODE (r) == BIND_EXPR))
+ {
+ r = copy_node (r);
+ SET_EXPR_LOCATION (r, loc);
+ }
+ x = r;
+ }
+
+ break;
+ }
+
+ if (VOID_TYPE_P (TREE_TYPE (x)))
+ break;
+
+ x = build3_loc (loc, code, TREE_TYPE (x), op0, op1, op2);
+
+ if (code != COND_EXPR)
+ x = fold (x);
+
+ break;
+
+ case CALL_EXPR:
+ {
+ int i, m, sv = optimize, nw = sv, changed = 0;
+ tree callee = get_callee_fndecl (x);
+
+ if (callee && DECL_BUILT_IN (callee) && !optimize
+ && DECL_IS_BUILTIN_CONSTANT_P (callee)
+ && current_function_decl
+ && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+ nw = 1;
+ optimize = nw;
+ r = fold (x);
+ optimize = sv;
+
+ if (TREE_CODE (r) != CALL_EXPR)
+ {
+ x = cp_fold (r, fold_hash);
+ break;
+ }
+
+ x = copy_node (x);
+
+ m = call_expr_nargs (x);
+ for (i = 0; i < m; i++)
+ {
+ r = cp_fold (CALL_EXPR_ARG (x, i), fold_hash);
+ if (r != CALL_EXPR_ARG (x, i))
+ changed = 1;
+ CALL_EXPR_ARG (x, i) = r;
+ }
+
+ optimize = nw;
+ r = fold (x);
+ optimize = sv;
+
+ if (TREE_CODE (r) != CALL_EXPR)
+ {
+ x = cp_fold (r, fold_hash);
+ break;
+ }
+
+ optimize = nw;
+
+ /* Invoke maybe_constant_value for functions being declared
+ constexpr, and are no AGGR_INIT_EXPRs ...
+ TODO:
+ Due issues in maybe_constant_value for CALL_EXPR with
+ arguments passed by reference, it is disabled. */
+ if (callee && DECL_DECLARED_CONSTEXPR_P (callee))
+ r = maybe_constant_value (x);
+ optimize = sv;
+
+ if (TREE_CODE (r) != CALL_EXPR)
+ {
+ x = r;
+ break;
+ }
+
+ if (!changed)
+ x = org_x;
+ break;
+ }
+
+ case BIND_EXPR:
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+ op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+ op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+
+ if (TREE_OPERAND (x, 0) != op0 || TREE_OPERAND (x, 1) != op1 || TREE_OPERAND (x, 2) != op2)
+ {
+ x = copy_node (x);
+ TREE_OPERAND (x, 0) = op0;
+ TREE_OPERAND (x, 1) = op1;
+ TREE_OPERAND (x, 2) = op2;
+ }
+ break;
+
+ case CONSTRUCTOR:
+ {
+ unsigned i;
+ constructor_elt *p;
+ vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (x);
+ FOR_EACH_VEC_SAFE_ELT (elts, i, p)
+ p->value = cp_fold (p->value, fold_hash);
+ break;
+ }
+ case TREE_VEC:
+ {
+ bool changed = false;
+ vec<tree, va_gc> *vec = make_tree_vector ();
+ int i, n = TREE_VEC_LENGTH (x);
+ vec_safe_reserve (vec, n);
+
+ for (i = 0; i < n; i++)
+ {
+ tree op = cp_fold (TREE_VEC_ELT (x, i), fold_hash);
+ vec->quick_push (op);
+ if (op != TREE_VEC_ELT (x, i))
+ changed = true;
+ }
+
+ if (changed)
+ {
+ r = copy_node (x);
+ for (i = 0; i < n; i++)
+ TREE_VEC_ELT (r, i) = (*vec)[i];
+ x = r;
+ }
+
+ release_tree_vector (vec);
+ }
+
+ break;
+
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+
+ loc = EXPR_LOCATION (x);
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+ op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+ op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+ op3 = cp_fold (TREE_OPERAND (x, 3), fold_hash);
+
+ if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1)
+ || op2 != TREE_OPERAND (x, 2) || op3 != TREE_OPERAND (x, 3))
+ x = build4_loc (loc, code, TREE_TYPE (x), op0, op1, op2, op3);
+
+ x = fold (x);
+ break;
+
+ case DECL_EXPR:
+
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+ if (op0 == TREE_OPERAND (x, 0))
+ break;
+
+ x = copy_node (x);
+ TREE_OPERAND (x, 0) = op0;
+ break;
+
+ default:
+ return org_x;
+ }
+
+ slot = &fold_hash->get_or_insert (org_x);
+ *slot = x;
+
+ /* Prevent that we try to fold an already folded result again. */
+ if (x != org_x)
+ {
+ slot = &fold_hash->get_or_insert (x);
+ *slot = x;
+ }
+
+ return x;
+}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 828f268..cc4148e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1239,6 +1239,11 @@ struct GTY(()) saved_scope {
hash_map<tree, tree> *GTY((skip)) x_local_specializations;
+ hash_map<tree, tree> *GTY((skip)) fold_map;
+ hash_map<tree, tree> *GTY((skip)) cv_map;
+
+ struct function *GTY((skip)) act_cfun;
+
struct saved_scope *prev;
};
@@ -6474,7 +6479,6 @@ extern tree cp_walk_subtrees (tree*, int*, walk_tree_fn,
walk_tree_1 (tp, func, data, pset, cp_walk_subtrees)
#define cp_walk_tree_without_duplicates(tp,func,data) \
walk_tree_without_duplicates_1 (tp, func, data, cp_walk_subtrees)
-extern tree fold_if_not_in_template (tree);
extern tree rvalue (tree);
extern tree convert_bitfield_to_declared_type (tree);
extern tree cp_save_expr (tree);
@@ -6705,6 +6709,7 @@ extern tree cxx_omp_clause_dtor (tree, tree);
extern void cxx_omp_finish_clause (tree, gimple_seq *);
extern bool cxx_omp_privatize_by_reference (const_tree);
extern bool cxx_omp_disregard_value_expr (tree, bool);
+extern tree cp_fully_fold (tree);
/* in name-lookup.c */
extern void suggest_alternatives_for (location_t, tree);
@@ -6796,12 +6801,14 @@ extern tree cxx_constant_value (tree, tree = NULL_TREE);
extern tree maybe_constant_value (tree, tree = NULL_TREE);
extern tree maybe_constant_init (tree, tree = NULL_TREE);
extern tree fold_non_dependent_expr (tree);
+extern tree fold_simple (tree);
extern bool is_sub_constant_expr (tree);
extern bool reduced_constant_expression_p (tree);
extern bool is_instantiation_of_constexpr (tree);
extern bool var_in_constexpr_fn (tree);
extern void explain_invalid_constexpr_fn (tree);
extern vec<tree> cx_error_context (void);
+extern tree fold_sizeof_expr (tree);
/* In c-family/cilk.c */
extern bool cilk_valid_spawn (tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index e764ee1..51b992c 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -53,7 +53,7 @@ static void diagnose_ref_binding (location_t, tree, tree, tree);
Here is a list of all the functions that assume that widening and
narrowing is always done with a NOP_EXPR:
- In convert.c, convert_to_integer.
+ In convert.c, convert_to_integer[_nofold].
In c-typeck.c, build_binary_op_nodefault (boolean ops),
and c_common_truthvalue_conversion.
In expr.c: expand_expr, for operands of a MULT_EXPR.
@@ -240,7 +240,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
gcc_assert (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr)))
== GET_MODE_SIZE (TYPE_MODE (type)));
- return convert_to_pointer (type, expr);
+ return convert_to_pointer_nofold (type, expr);
}
if (type_unknown_p (expr))
@@ -608,6 +608,7 @@ cp_fold_convert (tree type, tree expr)
conv = fold_convert (type, expr);
conv = ignore_overflows (conv, expr);
}
+
return conv;
}
@@ -633,7 +634,8 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
if (TREE_TYPE (expr) == type)
return expr;
-
+ if (expr == error_mark_node)
+ return expr;
result = cp_convert (type, expr, complain);
if ((complain & tf_warning)
@@ -641,13 +643,14 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
{
tree folded = maybe_constant_value (expr);
tree stripped = folded;
- tree folded_result
+ tree folded_result;
+ folded_result
= folded != expr ? cp_convert (type, folded, complain) : result;
-
- /* maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW in a
- NOP_EXPR so that it isn't TREE_CONSTANT anymore. */
+ folded_result = cp_fully_fold (folded_result);
+ /* The maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW
+ in a NOP_EXPR so that it isn't TREE_CONSTANT anymore. */
STRIP_NOPS (stripped);
-
+ folded = cp_fully_fold (folded);
if (!TREE_OVERFLOW_P (stripped)
&& folded_result != error_mark_node)
warnings_for_convert_and_check (input_location, type, folded,
@@ -706,9 +709,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
/* For complex data types, we need to perform componentwise
conversion. */
else if (TREE_CODE (type) == COMPLEX_TYPE)
- return fold_if_not_in_template (convert_to_complex (type, e));
+ return convert_to_complex_nofold (type, e);
else if (VECTOR_TYPE_P (type))
- return fold_if_not_in_template (convert_to_vector (type, e));
+ return convert_to_vector (type, e);
else if (TREE_CODE (e) == TARGET_EXPR)
{
/* Don't build a NOP_EXPR of class type. Instead, change the
@@ -721,7 +724,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
/* We shouldn't be treating objects of ADDRESSABLE type as
rvalues. */
gcc_assert (!TREE_ADDRESSABLE (type));
- return fold_if_not_in_template (build_nop (type, e));
+ return build_nop (type, e);
}
}
@@ -799,7 +802,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
return cp_truthvalue_conversion (e);
}
- converted = fold_if_not_in_template (convert_to_integer (type, e));
+ converted = convert_to_integer_nofold (type, e);
/* Ignore any integer overflow caused by the conversion. */
return ignore_overflows (converted, e);
@@ -811,7 +814,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
return nullptr_node;
}
if (POINTER_TYPE_P (type) || TYPE_PTRMEM_P (type))
- return fold_if_not_in_template (cp_convert_to_pointer (type, e, complain));
+ return cp_convert_to_pointer (type, e, complain);
if (code == VECTOR_TYPE)
{
tree in_vtype = TREE_TYPE (e);
@@ -826,7 +829,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
in_vtype, type);
return error_mark_node;
}
- return fold_if_not_in_template (convert_to_vector (type, e));
+ return convert_to_vector (type, e);
}
if (code == REAL_TYPE || code == COMPLEX_TYPE)
{
@@ -842,9 +845,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
TREE_TYPE (e));
}
if (code == REAL_TYPE)
- return fold_if_not_in_template (convert_to_real (type, e));
+ return convert_to_real_nofold (type, e);
else if (code == COMPLEX_TYPE)
- return fold_if_not_in_template (convert_to_complex (type, e));
+ return convert_to_complex_nofold (type, e);
}
/* New C++ semantics: since assignment is now based on
@@ -1457,7 +1460,7 @@ convert (tree type, tree expr)
intype = TREE_TYPE (expr);
if (POINTER_TYPE_P (type) && POINTER_TYPE_P (intype))
- return fold_if_not_in_template (build_nop (type, expr));
+ return build_nop (type, expr);
return ocp_convert (type, expr, CONV_OLD_CONVERT,
LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
@@ -1475,13 +1478,11 @@ convert_force (tree type, tree expr, int convtype, tsubst_flags_t complain)
enum tree_code code = TREE_CODE (type);
if (code == REFERENCE_TYPE)
- return (fold_if_not_in_template
- (convert_to_reference (type, e, CONV_C_CAST, 0,
- NULL_TREE, complain)));
+ return convert_to_reference (type, e, CONV_C_CAST, 0,
+ NULL_TREE, complain);
if (code == POINTER_TYPE)
- return fold_if_not_in_template (convert_to_pointer_force (type, e,
- complain));
+ return convert_to_pointer_force (type, e, complain);
/* From typeck.c convert_for_assignment */
if (((TYPE_PTR_P (TREE_TYPE (e)) && TREE_CODE (e) == ADDR_EXPR
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index bd3f2bc..484f4f2 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8580,35 +8580,6 @@ stabilize_vla_size (tree size)
cp_walk_tree (&size, stabilize_save_expr_r, &pset, &pset);
}
-/* Helper function for compute_array_index_type. Look for SIZEOF_EXPR
- not inside of SAVE_EXPR and fold them. */
-
-static tree
-fold_sizeof_expr_r (tree *expr_p, int *walk_subtrees, void *data)
-{
- tree expr = *expr_p;
- if (TREE_CODE (expr) == SAVE_EXPR || TYPE_P (expr))
- *walk_subtrees = 0;
- else if (TREE_CODE (expr) == SIZEOF_EXPR)
- {
- *(bool *)data = true;
- if (SIZEOF_EXPR_TYPE_P (expr))
- expr = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (expr, 0)),
- SIZEOF_EXPR, false);
- else if (TYPE_P (TREE_OPERAND (expr, 0)))
- expr = cxx_sizeof_or_alignof_type (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
- false);
- else
- expr = cxx_sizeof_or_alignof_expr (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
- false);
- if (expr == error_mark_node)
- expr = size_one_node;
- *expr_p = expr;
- *walk_subtrees = 0;
- }
- return NULL;
-}
-
/* Given the SIZE (i.e., number of elements) in an array, compute an
appropriate index type for the array. If non-NULL, NAME is the
name of the thing being declared. */
@@ -8699,7 +8670,18 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
SET_TYPE_STRUCTURAL_EQUALITY (itype);
return itype;
}
-
+
+ if (TREE_CODE (size) != INTEGER_CST)
+ {
+ tree folded = cp_fully_fold (size);
+ if (TREE_CODE (folded) == INTEGER_CST)
+ pedwarn (location_of (size), OPT_Wpedantic,
+ "size of array is not an integral constant-expression");
+ /* Use the folded result for VLAs, too; it will have resolved
+ SIZEOF_EXPR. */
+ size = folded;
+ }
+
/* Normally, the array-bound will be a constant. */
if (TREE_CODE (size) == INTEGER_CST)
{
@@ -8786,7 +8768,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
cp_convert (ssizetype, integer_one_node,
complain),
complain);
- itype = fold (itype);
+ itype = maybe_constant_value (itype);
processing_template_decl = saved_processing_template_decl;
if (!TREE_CONSTANT (itype))
@@ -8794,18 +8776,6 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
/* A variable sized array. */
itype = variable_size (itype);
- if (TREE_CODE (itype) != SAVE_EXPR)
- {
- /* Look for SIZEOF_EXPRs in itype and fold them, otherwise
- they might survive till gimplification. */
- tree newitype = itype;
- bool found = false;
- cp_walk_tree_without_duplicates (&newitype,
- fold_sizeof_expr_r, &found);
- if (found)
- itype = variable_size (fold (newitype));
- }
-
stabilize_vla_size (itype);
if (flag_sanitize & SANITIZE_VLA
@@ -13515,7 +13485,7 @@ incremented enumerator value is too large for %<long%>");
"type %<%T%>", value, ENUM_UNDERLYING_TYPE (enumtype));
/* Convert the value to the appropriate type. */
- value = convert (ENUM_UNDERLYING_TYPE (enumtype), value);
+ value = fold_convert (ENUM_UNDERLYING_TYPE (enumtype), value);
}
}
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a2d31a3..89859e9 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -3116,7 +3116,7 @@ get_guard_cond (tree guard, bool thread_safe)
{
guard_value = integer_one_node;
if (!same_type_p (TREE_TYPE (guard_value), TREE_TYPE (guard)))
- guard_value = convert (TREE_TYPE (guard), guard_value);
+ guard_value = fold_convert (TREE_TYPE (guard), guard_value);
guard = cp_build_binary_op (input_location,
BIT_AND_EXPR, guard, guard_value,
tf_warning_or_error);
@@ -3124,7 +3124,7 @@ get_guard_cond (tree guard, bool thread_safe)
guard_value = integer_zero_node;
if (!same_type_p (TREE_TYPE (guard_value), TREE_TYPE (guard)))
- guard_value = convert (TREE_TYPE (guard), guard_value);
+ guard_value = fold_convert (TREE_TYPE (guard), guard_value);
return cp_build_binary_op (input_location,
EQ_EXPR, guard, guard_value,
tf_warning_or_error);
@@ -3142,7 +3142,7 @@ set_guard (tree guard)
guard = get_guard_bits (guard);
guard_init = integer_one_node;
if (!same_type_p (TREE_TYPE (guard_init), TREE_TYPE (guard)))
- guard_init = convert (TREE_TYPE (guard), guard_init);
+ guard_init = fold_convert (TREE_TYPE (guard), guard_init);
return cp_build_modify_expr (guard, NOP_EXPR, guard_init,
tf_warning_or_error);
}
@@ -4573,6 +4573,19 @@ c_parse_final_cleanups (void)
/* If there are templates that we've put off instantiating, do
them now. */
instantiate_pending_templates (retries);
+ /* Clear fold_map and/or cv_map of current scope, if present. */
+ if (scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+ {
+ hash_map<tree,tree> *fm = scope_chain->fold_map;
+ hash_map<tree,tree> *cv = scope_chain->cv_map;
+ scope_chain->fold_map = NULL;
+ scope_chain->cv_map = NULL;
+ scope_chain->act_cfun = NULL;
+ if (fm)
+ delete fm;
+ if (cv)
+ delete cv;
+ }
ggc_collect ();
/* Write out virtual tables as required. Note that writing out
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index b45281f..fd9ae0d 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -178,9 +178,9 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
initialized are initialized to zero. */
;
else if (TYPE_PTR_OR_PTRMEM_P (type))
- init = convert (type, nullptr_node);
+ init = fold (convert (type, nullptr_node));
else if (SCALAR_TYPE_P (type))
- init = convert (type, integer_zero_node);
+ init = fold (convert (type, integer_zero_node));
else if (RECORD_OR_UNION_CODE_P (TREE_CODE (type)))
{
tree field;
@@ -794,7 +794,6 @@ perform_member_init (tree member, tree init)
in that case. */
init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
tf_warning_or_error);
-
if (init)
finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init,
tf_warning_or_error));
@@ -2712,7 +2711,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
}
max_outer_nelts_tree = wide_int_to_tree (sizetype, max_outer_nelts);
- size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
+ size = size_binop (MULT_EXPR, size, fold_convert (sizetype, nelts));
outer_nelts_check = fold_build2 (LE_EXPR, boolean_type_node,
outer_nelts,
max_outer_nelts_tree);
@@ -2872,7 +2871,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
{
placement_expr = get_target_expr (placement_first);
CALL_EXPR_ARG (alloc_call, 1)
- = convert (TREE_TYPE (placement), placement_expr);
+ = fold_convert (TREE_TYPE (placement), placement_expr);
}
if (!member_new_p
@@ -3464,7 +3463,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
/* The below is short by the cookie size. */
virtual_size = size_binop (MULT_EXPR, size_exp,
- convert (sizetype, maxindex));
+ fold_convert (sizetype, maxindex));
tbase = create_temporary_var (ptype);
tbase_init
@@ -3507,7 +3506,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
/* The below is short by the cookie size. */
virtual_size = size_binop (MULT_EXPR, size_exp,
- convert (sizetype, maxindex));
+ fold_convert (sizetype, maxindex));
if (! TYPE_VEC_NEW_USES_COOKIE (type))
/* no header */
@@ -3553,8 +3552,8 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
body = fold_build3_loc (input_location, COND_EXPR, void_type_node,
fold_build2_loc (input_location,
NE_EXPR, boolean_type_node, base,
- convert (TREE_TYPE (base),
- nullptr_node)),
+ fold_convert (TREE_TYPE (base),
+ nullptr_node)),
body, integer_zero_node);
body = build1 (NOP_EXPR, void_type_node, body);
@@ -3676,6 +3675,7 @@ build_vec_init (tree base, tree maxindex, tree init,
if (maxindex == NULL_TREE || maxindex == error_mark_node)
return error_mark_node;
+ maxindex = maybe_constant_value (maxindex);
if (explicit_value_init_p)
gcc_assert (!init);
@@ -3717,6 +3717,8 @@ build_vec_init (tree base, tree maxindex, tree init,
}
maxindex = cp_convert (ptrdiff_type_node, maxindex, complain);
+ maxindex = fold_simple (maxindex);
+
if (TREE_CODE (atype) == ARRAY_TYPE)
{
ptype = build_pointer_type (type);
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 8744fff..61a352a 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -6182,6 +6182,19 @@ push_to_top_level (void)
s->unevaluated_operand = cp_unevaluated_operand;
s->inhibit_evaluation_warnings = c_inhibit_evaluation_warnings;
s->x_stmt_tree.stmts_are_full_exprs_p = true;
+ if (current_function_decl
+ && scope_chain && scope_chain->function_decl == current_function_decl
+ && cfun && scope_chain->act_cfun == cfun)
+ {
+ s->fold_map = scope_chain->fold_map;
+ s->cv_map = scope_chain->cv_map;
+ }
+ else
+ {
+ s->fold_map = NULL;
+ s->cv_map = NULL;
+ }
+ s->act_cfun = cfun;
scope_chain = s;
current_function_decl = NULL_TREE;
@@ -6199,7 +6212,10 @@ pop_from_top_level_1 (void)
{
struct saved_scope *s = scope_chain;
cxx_saved_binding *saved;
+ hash_map<tree, tree> *fm = s->fold_map;
+ hash_map<tree, tree> *cv = s->cv_map;
size_t i;
+ bool same_fold_map = false;
/* Clear out class-level bindings cache. */
if (previous_class_level)
@@ -6221,9 +6237,32 @@ pop_from_top_level_1 (void)
state. */
if (s->need_pop_function_context)
pop_function_context ();
+
+ /* If 'current_function_decl' isn't NULL and is equal to prior pushed,
+ we are within a nested function.
+ If additionally saved 'cfun' is identical to current, we can use
+ the same 'fold_map'. */
+
+ if (current_function_decl && s->function_decl == current_function_decl
+ && scope_chain && s->fold_map == scope_chain->fold_map
+ && scope_chain->act_cfun && scope_chain->act_cfun == cfun)
+ same_fold_map = true;
+
current_function_decl = s->function_decl;
cp_unevaluated_operand = s->unevaluated_operand;
c_inhibit_evaluation_warnings = s->inhibit_evaluation_warnings;
+
+ /* If we have a new 'fold_map', and it isn't equal, or outside of
+ scope_chain, then invalidate it. */
+ if (fm && (!same_fold_map || !scope_chain))
+ delete fm;
+ if (cv && (!same_fold_map || !scope_chain))
+ delete cv;
+
+ /* Invalidate explicit. */
+ s->fold_map = NULL;
+ s->cv_map = NULL;
+ s->act_cfun = NULL;
}
/* Wrapper for pop_from_top_level_1. */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d1f4970..24a77f8 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -6769,7 +6769,7 @@ cp_parser_array_notation (location_t loc, cp_parser *parser, tree *init_index,
2. ARRAY [ EXP : EXP ]
3. ARRAY [ EXP : EXP : EXP ] */
- *init_index = cp_parser_expression (parser);
+ *init_index = cp_parser_expression (parser);
if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON)
{
/* This indicates that we have a normal array expression. */
@@ -8513,9 +8513,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
/* For "false && x" or "true || x", x will never be executed;
disable warnings while evaluating it. */
if (current.tree_type == TRUTH_ANDIF_EXPR)
- c_inhibit_evaluation_warnings += current.lhs == truthvalue_false_node;
+ c_inhibit_evaluation_warnings +=
+ cp_fully_fold (current.lhs) == truthvalue_false_node;
else if (current.tree_type == TRUTH_ORIF_EXPR)
- c_inhibit_evaluation_warnings += current.lhs == truthvalue_true_node;
+ c_inhibit_evaluation_warnings +=
+ cp_fully_fold (current.lhs) == truthvalue_true_node;
/* Extract another operand. It may be the RHS of this expression
or the LHS of a new, higher priority expression. */
@@ -8562,9 +8564,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
/* Undo the disabling of warnings done above. */
if (current.tree_type == TRUTH_ANDIF_EXPR)
- c_inhibit_evaluation_warnings -= current.lhs == truthvalue_false_node;
+ c_inhibit_evaluation_warnings -=
+ cp_fully_fold (current.lhs) == truthvalue_false_node;
else if (current.tree_type == TRUTH_ORIF_EXPR)
- c_inhibit_evaluation_warnings -= current.lhs == truthvalue_true_node;
+ c_inhibit_evaluation_warnings -=
+ cp_fully_fold (current.lhs) == truthvalue_true_node;
if (warn_logical_not_paren
&& TREE_CODE_CLASS (current.tree_type) == tcc_comparison
@@ -8650,7 +8654,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
static tree
cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
{
- tree expr;
+ tree expr, folded_logical_or_expr = cp_fully_fold (logical_or_expr);
tree assignment_expr;
struct cp_token *token;
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -8665,7 +8669,8 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
"ISO C++ does not allow ?: with omitted middle operand");
/* Implicit true clause. */
expr = NULL_TREE;
- c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_true_node;
+ c_inhibit_evaluation_warnings +=
+ folded_logical_or_expr == truthvalue_true_node;
warn_for_omitted_condop (token->location, logical_or_expr);
}
else
@@ -8673,11 +8678,12 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
parser->colon_corrects_to_scope_p = false;
/* Parse the expression. */
- c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_false_node;
+ c_inhibit_evaluation_warnings +=
+ folded_logical_or_expr == truthvalue_false_node;
expr = cp_parser_expression (parser);
c_inhibit_evaluation_warnings +=
- ((logical_or_expr == truthvalue_true_node)
- - (logical_or_expr == truthvalue_false_node));
+ ((folded_logical_or_expr == truthvalue_true_node)
+ - (folded_logical_or_expr == truthvalue_false_node));
parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
}
@@ -8685,7 +8691,8 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
cp_parser_require (parser, CPP_COLON, RT_COLON);
/* Parse the assignment-expression. */
assignment_expr = cp_parser_assignment_expression (parser);
- c_inhibit_evaluation_warnings -= logical_or_expr == truthvalue_true_node;
+ c_inhibit_evaluation_warnings -=
+ folded_logical_or_expr == truthvalue_true_node;
/* Build the conditional-expression. */
return build_x_conditional_expr (loc, logical_or_expr,
@@ -20330,8 +20337,8 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
{
initializer
= cp_parser_constant_expression (parser,
- /*allow_non_constant_p=*/true,
- non_constant_p);
+ /*allow_non_constant_p=*/true,
+ non_constant_p);
}
else
initializer = cp_parser_braced_list (parser, non_constant_p);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index bfea8e2..fb9cdf8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6217,7 +6217,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
/* 14.3.2/5: The null pointer{,-to-member} conversion is applied
to a non-type argument of "nullptr". */
if (expr == nullptr_node && TYPE_PTR_OR_PTRMEM_P (type))
- expr = convert (type, expr);
+ expr = fold_simple (convert (type, expr));
/* In C++11, integral or enumeration non-type template arguments can be
arbitrary constant expressions. Pointer and pointer to
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7702a41..73f05f0 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2569,9 +2569,26 @@ 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);
+ tree result_ovl, expr_ovl;
+
+ if (!(complain & tf_warning))
+ return result;
+
+ result_ovl = result;
+ expr_ovl = expr;
+
+ if (!processing_template_decl)
+ expr_ovl = cp_fully_fold (expr_ovl);
+
+ if (!CONSTANT_CLASS_P (expr_ovl)
+ || TREE_OVERFLOW_P (expr_ovl))
+ return result;
+
+ if (!processing_template_decl)
+ result_ovl = cp_fully_fold (result_ovl);
+
+ if (CONSTANT_CLASS_P (result_ovl) && TREE_OVERFLOW_P (result_ovl))
+ overflow_warning (input_location, result_ovl);
return result;
}
@@ -3895,6 +3912,7 @@ finish_offsetof (tree expr, location_t loc)
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)
@@ -4049,6 +4067,22 @@ emit_associated_thunks (tree fn)
bool
expand_or_defer_fn_1 (tree fn)
{
+ if (!function_depth)
+ {
+ if (scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+ {
+ hash_map<tree, tree> *fm = scope_chain->fold_map;
+ hash_map<tree, tree> *cv = scope_chain->cv_map;
+ if (fm)
+ delete fm;
+ if (cv)
+ delete cv;
+ scope_chain->fold_map = NULL;
+ scope_chain->cv_map = NULL;
+ scope_chain->act_cfun = NULL;
+ }
+ }
+
/* 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)
@@ -4129,6 +4163,19 @@ expand_or_defer_fn (tree fn)
emit_associated_thunks (fn);
function_depth--;
+ if (function_depth == 0
+ && scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+ {
+ hash_map<tree, tree> *fm = scope_chain->fold_map;
+ hash_map<tree, tree> *cv = scope_chain->cv_map;
+ scope_chain->fold_map = NULL;
+ scope_chain->cv_map = NULL;
+ scope_chain->act_cfun = NULL;
+ if (fm)
+ delete fm;
+ if (cv)
+ delete cv;
+ }
}
}
@@ -4483,6 +4530,11 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
low_bound = mark_rvalue_use (low_bound);
if (length)
length = mark_rvalue_use (length);
+ /* We need to reduce to real constant-values for checks below. */
+ if (length)
+ length = fold_simple (length);
+ if (low_bound)
+ low_bound = fold_simple (low_bound);
if (low_bound
&& TREE_CODE (low_bound) == INTEGER_CST
&& TYPE_PRECISION (TREE_TYPE (low_bound))
@@ -6178,7 +6230,8 @@ finish_omp_clauses (tree clauses, bool allow_fields, bool declare_simd)
if (OMP_CLAUSE_SCHEDULE_KIND (c)
== OMP_CLAUSE_SCHEDULE_CILKFOR)
{
- t = convert_to_integer (long_integer_type_node, t);
+ t = convert_to_integer_nofold (long_integer_type_node,
+ t);
if (t == error_mark_node)
{
remove = true;
@@ -7447,6 +7500,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
if (init && EXPR_HAS_LOCATION (init))
elocus = EXPR_LOCATION (init);
+ cond = cp_fully_fold (cond);
switch (TREE_CODE (cond))
{
case GT_EXPR:
@@ -7482,6 +7536,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
diff = build_x_binary_op (elocus, MINUS_EXPR, TREE_OPERAND (cond, 1),
ERROR_MARK, iter, ERROR_MARK, NULL,
tf_warning_or_error);
+ diff = cp_fully_fold (diff);
if (error_operand_p (diff))
return true;
if (TREE_CODE (TREE_TYPE (diff)) != INTEGER_TYPE)
@@ -7543,8 +7598,9 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
if (TREE_CODE (rhs) == MINUS_EXPR)
{
incr = build1 (NEGATE_EXPR, TREE_TYPE (diff), incr);
- incr = fold_if_not_in_template (incr);
+ incr = fold_simple (incr);
}
+
if (TREE_CODE (incr) != INTEGER_CST
&& (TREE_CODE (incr) != NOP_EXPR
|| (TREE_CODE (TREE_OPERAND (incr, 0))
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 4311212..dd4daed 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -308,9 +308,19 @@ xvalue_p (const_tree ref)
bool
builtin_valid_in_constant_expr_p (const_tree decl)
{
- /* At present BUILT_IN_CONSTANT_P is the only builtin we're allowing
- in constant-expressions. We may want to add other builtins later. */
- return DECL_IS_BUILTIN_CONSTANT_P (decl);
+ if (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl)))
+ /* Not a built-in. */
+ return false;
+ switch (DECL_FUNCTION_CODE (decl))
+ {
+ case BUILT_IN_CONSTANT_P:
+ case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
+ /* These have constant results even if their operands are
+ non-constant. */
+ return true;
+ default:
+ return false;
+ }
}
/* Build a TARGET_EXPR, initializing the DECL with the VALUE. */
@@ -686,8 +696,8 @@ convert_bitfield_to_declared_type (tree expr)
bitfield_type = is_bitfield_expr_with_lowered_type (expr);
if (bitfield_type)
- expr = convert_to_integer (TYPE_MAIN_VARIANT (bitfield_type),
- expr);
+ expr = convert_to_integer_nofold (TYPE_MAIN_VARIANT (bitfield_type),
+ expr);
return expr;
}
@@ -3484,10 +3494,13 @@ handle_init_priority_attribute (tree* node,
STRIP_NOPS (initp_expr);
initp_expr = default_conversion (initp_expr);
+ if (initp_expr)
+ initp_expr = maybe_constant_value (initp_expr);
if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
{
error ("requested init_priority is not an integer constant");
+ cxx_constant_value (initp_expr);
*no_add_attrs = true;
return NULL_TREE;
}
@@ -4262,26 +4275,6 @@ stabilize_init (tree init, tree *initp)
return !TREE_SIDE_EFFECTS (init);
}
-/* Like "fold", but should be used whenever we might be processing the
- body of a template. */
-
-tree
-fold_if_not_in_template (tree expr)
-{
- /* In the body of a template, there is never any need to call
- "fold". We will call fold later when actually instantiating the
- template. Integral constant expressions in templates will be
- evaluated via instantiate_non_dependent_expr, as necessary. */
- if (processing_template_decl)
- return expr;
-
- /* Fold C++ front-end specific tree codes. */
- if (TREE_CODE (expr) == UNARY_PLUS_EXPR)
- return fold_convert (TREE_TYPE (expr), TREE_OPERAND (expr, 0));
-
- return fold (expr);
-}
-
/* Returns true if a cast to TYPE may appear in an integral constant
expression. */
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 0501e4d..4e7ef58 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1948,8 +1948,6 @@ decay_conversion (tree exp,
code = TREE_CODE (type);
- /* FIXME remove for delayed folding. */
- exp = scalar_constant_value (exp);
if (error_operand_p (exp))
return error_mark_node;
@@ -2442,7 +2440,6 @@ build_class_member_access_expr (tree object, tree member,
result = build3_loc (input_location, COMPONENT_REF, member_type,
object, member, NULL_TREE);
- result = fold_if_not_in_template (result);
/* Mark the expression const or volatile, as appropriate. Even
though we've dealt with the type above, we still have to mark the
@@ -2855,9 +2852,9 @@ build_simple_component_ref (tree object, tree member)
{
tree type = cp_build_qualified_type (TREE_TYPE (member),
cp_type_quals (TREE_TYPE (object)));
- return fold_build3_loc (input_location,
- COMPONENT_REF, type,
- object, member, NULL_TREE);
+ return build3_loc (input_location,
+ COMPONENT_REF, type,
+ object, member, NULL_TREE);
}
/* Return an expression for the MEMBER_NAME field in the internal
@@ -3176,8 +3173,7 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
TREE_THIS_VOLATILE (rval)
|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
- ret = require_complete_type_sfinae (fold_if_not_in_template (rval),
- complain);
+ ret = require_complete_type_sfinae (rval, complain);
protected_set_expr_location (ret, loc);
if (non_lvalue)
ret = non_lvalue_loc (loc, ret);
@@ -3924,7 +3920,6 @@ build_vec_cmp (tree_code code, tree type,
tree minus_one_vec = build_minus_one_cst (type);
tree cmp_type = build_same_sized_truth_vector_type(type);
tree cmp = build2 (code, cmp_type, arg0, arg1);
- cmp = fold_if_not_in_template (cmp);
return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
}
@@ -3979,7 +3974,7 @@ cp_build_binary_op (location_t location,
convert it to this type. */
tree final_type = 0;
- tree result;
+ tree result, result_ovl;
tree orig_type = NULL;
/* Nonzero if this is an operation like MIN or MAX which can
@@ -4602,7 +4597,7 @@ cp_build_binary_op (location_t location,
op0 = cp_build_binary_op (location,
TRUTH_ANDIF_EXPR, e1, e2,
complain);
- op1 = cp_convert (TREE_TYPE (op0), integer_one_node, complain);
+ op1 = cp_convert (TREE_TYPE (op0), integer_one_node, complain);
}
else
{
@@ -4643,10 +4638,12 @@ cp_build_binary_op (location_t location,
op1 = save_expr (op1);
pfn0 = pfn_from_ptrmemfunc (op0);
+ pfn0 = cp_fully_fold (pfn0);
/* Avoid -Waddress warnings (c++/64877). */
if (TREE_CODE (pfn0) == ADDR_EXPR)
TREE_NO_WARNING (pfn0) = 1;
pfn1 = pfn_from_ptrmemfunc (op1);
+ pfn1 = cp_fully_fold (pfn1);
delta0 = delta_from_ptrmemfunc (op0);
delta1 = delta_from_ptrmemfunc (op1);
if (TARGET_PTRMEMFUNC_VBIT_LOCATION
@@ -5000,10 +4997,7 @@ cp_build_binary_op (location_t location,
gcc_unreachable();
}
}
- real = fold_if_not_in_template (real);
- imag = fold_if_not_in_template (imag);
result = build2 (COMPLEX_EXPR, result_type, real, imag);
- result = fold_if_not_in_template (result);
return result;
}
@@ -5031,20 +5025,12 @@ cp_build_binary_op (location_t location,
if (short_compare)
{
- /* Don't write &op0, etc., because that would prevent op0
- from being kept in a register.
- Instead, make copies of the our local variables and
- pass the copies by reference, then copy them back afterward. */
- tree xop0 = op0, xop1 = op1, xresult_type = result_type;
+ /* We call shorten_compare only for diagnostic-reason. */
+ tree xop0 = fold_simple (op0), xop1 = fold_simple (op1),
+ xresult_type = result_type;
enum tree_code xresultcode = resultcode;
- tree val
- = shorten_compare (location, &xop0, &xop1, &xresult_type,
+ shorten_compare (location, &xop0, &xop1, &xresult_type,
&xresultcode);
- if (val != 0)
- return cp_convert (boolean_type_node, val, complain);
- op0 = xop0, op1 = xop1;
- converted = 1;
- resultcode = xresultcode;
}
if ((short_compare || code == MIN_EXPR || code == MAX_EXPR)
@@ -5063,9 +5049,9 @@ cp_build_binary_op (location_t location,
tree oop1 = maybe_constant_value (orig_op1);
if (TREE_CODE (oop0) != INTEGER_CST)
- oop0 = orig_op0;
+ oop0 = cp_fully_fold (orig_op0);
if (TREE_CODE (oop1) != INTEGER_CST)
- oop1 = orig_op1;
+ oop1 = cp_fully_fold (orig_op1);
warn_for_sign_compare (location, oop0, oop1, op0, op1,
result_type, resultcode);
}
@@ -5120,18 +5106,30 @@ cp_build_binary_op (location_t location,
}
result = build2 (resultcode, build_type, op0, op1);
- result = fold_if_not_in_template (result);
if (final_type != 0)
result = cp_convert (final_type, result, complain);
- if (TREE_OVERFLOW_P (result)
- && !TREE_OVERFLOW_P (op0)
- && !TREE_OVERFLOW_P (op1))
- overflow_warning (location, result);
-
if (instrument_expr != NULL)
- result = fold_build2 (COMPOUND_EXPR, TREE_TYPE (result),
- instrument_expr, result);
+ result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
+ instrument_expr, result);
+
+ if (!processing_template_decl)
+ {
+ op0 = cp_fully_fold (op0);
+ /* Only consider the second argument if the first isn't overflowed. */
+ if (!CONSTANT_CLASS_P (op0) || TREE_OVERFLOW_P (op0))
+ return result;
+ op1 = cp_fully_fold (op1);
+ if (!CONSTANT_CLASS_P (op1) || TREE_OVERFLOW_P (op1))
+ return result;
+ }
+ else if (!CONSTANT_CLASS_P (op0) || !CONSTANT_CLASS_P (op1)
+ || TREE_OVERFLOW_P (op0) || TREE_OVERFLOW_P (op1))
+ return result;
+
+ result_ovl = fold_build2 (resultcode, build_type, op0, op1);
+ if (TREE_OVERFLOW_P (result_ovl))
+ overflow_warning (location, result_ovl);
return result;
}
@@ -5181,8 +5179,7 @@ cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop,
complete_type (TREE_TYPE (res_type));
return pointer_int_sum (input_location, resultcode, ptrop,
- fold_if_not_in_template (intop),
- complain & tf_warning_or_error);
+ intop, complain & tf_warning_or_error);
}
/* Return a tree for the difference of pointers OP0 and OP1.
@@ -5258,7 +5255,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
result = build2 (EXACT_DIV_EXPR, restype, op0,
cp_convert (restype, op1, complain));
- return fold_if_not_in_template (result);
+ return result;
}
/* Construct and perhaps optimize a tree representation
@@ -5774,6 +5771,10 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
/* Make sure the result is not an lvalue: a unary plus or minus
expression is always a rvalue. */
arg = rvalue (arg);
+
+ if (code == NEGATE_EXPR && CONSTANT_CLASS_P (arg))
+ /* Immediately fold negation of a constant. */
+ return fold_build1 (code, TREE_TYPE (arg), arg);
}
}
break;
@@ -5838,10 +5839,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
case REALPART_EXPR:
case IMAGPART_EXPR:
arg = build_real_imag_expr (input_location, code, arg);
- if (arg == error_mark_node)
- return arg;
- else
- return fold_if_not_in_template (arg);
+ return arg;
case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
@@ -6008,7 +6006,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
{
if (argtype == 0)
argtype = TREE_TYPE (arg);
- return fold_if_not_in_template (build1 (code, argtype, arg));
+ return build1 (code, argtype, arg);
}
if (complain & tf_error)
@@ -7002,7 +7000,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
return rvalue (expr);
else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
- return fold_if_not_in_template (build_nop (type, expr));
+ return build_nop (type, expr);
else if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype))
|| (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
{
@@ -7030,7 +7028,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
if (warn_strict_aliasing <= 2)
strict_aliasing_warning (intype, type, sexpr);
- return fold_if_not_in_template (build_nop (type, expr));
+ return build_nop (type, expr);
}
else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
|| (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
@@ -7041,13 +7039,13 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
warning (OPT_Wconditionally_supported,
"casting between pointer-to-function and pointer-to-object "
"is conditionally-supported");
- return fold_if_not_in_template (build_nop (type, expr));
+ return build_nop (type, expr);
}
else if (VECTOR_TYPE_P (type))
- return fold_if_not_in_template (convert_to_vector (type, expr));
+ return convert_to_vector (type, expr);
else if (VECTOR_TYPE_P (intype)
&& INTEGRAL_OR_ENUMERATION_TYPE_P (type))
- return fold_if_not_in_template (convert_to_integer (type, expr));
+ return convert_to_integer_nofold (type, expr);
else
{
if (valid_p)
@@ -7899,8 +7897,7 @@ get_delta_difference (tree from, tree to,
}
}
- return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node,
- result));
+ return convert_to_integer (ptrdiff_type_node, result);
}
/* Return a constructor for the pointer-to-member-function TYPE using
@@ -8081,41 +8078,35 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
fn; the call will do the opposite adjustment. */
tree orig_class = DECL_CONTEXT (fn);
tree binfo = binfo_or_else (orig_class, fn_class);
- *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
- *delta, BINFO_OFFSET (binfo));
- *delta = fold_if_not_in_template (*delta);
+ *delta = fold_build2 (PLUS_EXPR, TREE_TYPE (*delta),
+ *delta, BINFO_OFFSET (binfo));
/* We set PFN to the vtable offset at which the function can be
found, plus one (unless ptrmemfunc_vbit_in_delta, in which
case delta is shifted left, and then incremented). */
*pfn = DECL_VINDEX (fn);
- *pfn = build2 (MULT_EXPR, integer_type_node, *pfn,
- TYPE_SIZE_UNIT (vtable_entry_type));
- *pfn = fold_if_not_in_template (*pfn);
+ *pfn = fold_build2 (MULT_EXPR, integer_type_node, *pfn,
+ TYPE_SIZE_UNIT (vtable_entry_type));
switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
{
case ptrmemfunc_vbit_in_pfn:
- *pfn = build2 (PLUS_EXPR, integer_type_node, *pfn,
- integer_one_node);
- *pfn = fold_if_not_in_template (*pfn);
+ *pfn = fold_build2 (PLUS_EXPR, integer_type_node, *pfn,
+ integer_one_node);
break;
case ptrmemfunc_vbit_in_delta:
- *delta = build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
- *delta, integer_one_node);
- *delta = fold_if_not_in_template (*delta);
- *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
- *delta, integer_one_node);
- *delta = fold_if_not_in_template (*delta);
+ *delta = fold_build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
+ *delta, integer_one_node);
+ *delta = fold_build2 (PLUS_EXPR, TREE_TYPE (*delta),
+ *delta, integer_one_node);
break;
default:
gcc_unreachable ();
}
- *pfn = build_nop (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
- *pfn = fold_if_not_in_template (*pfn);
+ *pfn = fold_convert (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
}
}
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index e73ea13..7544333 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -742,6 +742,7 @@ split_nonconstant_init (tree dest, tree init)
init = TARGET_EXPR_INITIAL (init);
if (TREE_CODE (init) == CONSTRUCTOR)
{
+ init = cp_fully_fold (init);
code = push_stmt_list ();
if (split_nonconstant_init_1 (dest, init))
init = NULL_TREE;
@@ -832,6 +833,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init;
TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
}
+ value = cp_fully_fold (value);
if (cxx_dialect >= cxx14 && CLASS_TYPE_P (strip_array_types (type)))
/* Handle aggregate NSDMI in non-constant initializers, too. */
@@ -930,19 +932,35 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
}
}
+ bool almost_ok = ok;
+ if (!ok && !CONSTANT_CLASS_P (init) && (complain & tf_warning_or_error))
+ {
+ tree folded = cp_fully_fold (init);
+ if (TREE_CONSTANT (folded) && check_narrowing (type, folded, tf_none))
+ almost_ok = true;
+ }
+
if (!ok)
{
+ location_t loc = EXPR_LOC_OR_LOC (init, input_location);
if (cxx_dialect == cxx98)
- warning_at (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
- "narrowing conversion of %qE from %qT to %qT inside { } "
- "is ill-formed in C++11", init, ftype, type);
- else if (!TREE_CONSTANT (init))
+ {
+ if (complain & tf_warning)
+ warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
+ "from %qT to %qT inside { } is ill-formed in C++11",
+ init, ftype, type);
+ ok = true;
+ }
+ else if (!CONSTANT_CLASS_P (init))
{
if (complain & tf_warning_or_error)
{
- pedwarn (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
- "narrowing conversion of %qE from %qT to %qT inside { }",
- init, ftype, type);
+ if (!almost_ok || pedantic)
+ pedwarn (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
+ "from %qT to %qT inside { }", init, ftype, type);
+ if (pedantic && almost_ok)
+ inform (loc, " the expression has a constant value but is not "
+ "a C++ constant-expression");
ok = true;
}
}
@@ -950,7 +968,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
{
int savederrorcount = errorcount;
global_dc->pedantic_errors = 1;
- pedwarn (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
+ pedwarn (loc, OPT_Wnarrowing,
"narrowing conversion of %qE from %qT to %qT "
"inside { }", init, ftype, type);
if (errorcount == savederrorcount)
@@ -959,7 +977,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
}
}
- return cxx_dialect == cxx98 || ok;
+ return ok;
}
/* Process the initializer INIT for a variable of type TYPE, emitting
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5e32901..d754a90 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -2091,6 +2091,17 @@ fold_convert_const (enum tree_code code, tree type, tree arg1)
else if (TREE_CODE (arg1) == REAL_CST)
return fold_convert_const_fixed_from_real (type, arg1);
}
+ else if (TREE_CODE (type) == VECTOR_TYPE)
+ {
+ if (TREE_CODE (arg1) == VECTOR_CST
+ && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (arg1))
+ && TYPE_VECTOR_SUBPARTS (type) == VECTOR_CST_NELTS (arg1))
+ {
+ tree r = copy_node (arg1);
+ TREE_TYPE (arg1) = type;
+ return r;
+ }
+ }
return NULL_TREE;
}
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
index 5d803ad..8f14034 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
@@ -47,3 +47,5 @@ right (int x)
r += -1U >> x;
return r;
}
+
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
index fc89af1..55523a5 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
@@ -47,3 +47,6 @@ right (int x)
r += -1U >> x;
return r;
}
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
index bf9b1a0..1295b72 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
@@ -47,3 +47,6 @@ right (int x)
r += -1U >> x;
return r;
}
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
index 85fbd0e..3088220 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
@@ -47,3 +47,6 @@ right (int x)
r += -1U >> x;
return r;
}
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/fold-bitand-4.c b/gcc/testsuite/c-c++-common/fold-bitand-4.c
index 1b9c388..a658ff1 100644
--- a/gcc/testsuite/c-c++-common/fold-bitand-4.c
+++ b/gcc/testsuite/c-c++-common/fold-bitand-4.c
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c } } } */
/* { dg-options "-fdump-tree-original" } */
/* { dg-additional-options "-fno-common" { target hppa*-*-hpux* } } */
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
index 26c9293..a5e3c1f1 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
@@ -18,7 +18,7 @@ public:
{
/* I am surprised this is considered a constexpr */
return *((Inner *)4);
- } // { dg-error "reinterpret_cast" "" { xfail *-*-* } }
+ } // { dg-error "reinterpret_cast" "" }
};
B B::instance;
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr53792.C b/gcc/testsuite/g++.dg/cpp0x/pr53792.C
new file mode 100644
index 0000000..deb5c1a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr53792.C
@@ -0,0 +1,29 @@
+// PR c++/53792
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -fdump-tree-optimized" }
+// { dg-final { scan-tree-dump "return 0" "optimized" } }
+
+struct entry {
+ char const* label;
+ int value;
+};
+
+constexpr bool same(char const *x, char const *y) {
+ return !*x && !*y ? true
+ : /* default */ (*x == *y && same(x+1, y+1));
+}
+
+constexpr int keyToValue(char const *label, entry const *entries) {
+ return !entries->label ? entries->value
+ : same(entries->label, label) ? entries->value
+ : /*default*/ keyToValue(label, entries+1);
+}
+
+constexpr entry foo[] = {{"Foo", 0}, {"Bar", 1}, {"FooBar", 2}, {0, -1}};
+
+int
+bar()
+{
+ int result = keyToValue("Foo", foo);
+ return result;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp b/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp
new file mode 100644
index 0000000..afa7edb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+
+constexpr int f(void *) { return 0; }
+constexpr int f(...) { return 1; }
+constexpr int g1() { return f(0); }
+constexpr int g2(int n) { return f(n); }
+constexpr int g3(int n) { return f(n*0); }
+
+int main()
+{
+ static_assert(g1() == 0, "g1 failed");
+ static_assert(g2(0) == 1, "g2 failed");
+ static_assert(g3(0) == 1, "g3 failed");
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C b/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C
new file mode 100644
index 0000000..e340de4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -Woverflow" }
+
+#include <climits>
+
+constexpr int f() { return INT_MIN; }
+
+int main()
+{
+ return -f(); // { dg-warning "overflow" }
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C b/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C
new file mode 100644
index 0000000..6b5dff8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -Woverflow" }
+
+#include <climits>
+
+constexpr int f() { return INT_MAX; }
+
+int main()
+{
+ return f() + 2; // { dg-warning "overflow" }
+}
+
diff --git a/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C
new file mode 100644
index 0000000..39b3557
--- /dev/null
+++ b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -Werror" } */
+
+extern int fl;
+
+#define MAK (fl < 0 ? 1 : (fl ? -1 : 0))
+
+int foo (int sz)
+{
+ if (MAK) return 1;
+ return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C
new file mode 100644
index 0000000..fa91a4f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -Werror" } */
+
+extern int fl;
+extern int arr[];
+
+#define MAK (fl < 0 ? 1 : (fl ? 2 : 0))
+
+int foo (int sz)
+{
+ unsigned i;
+ int r = 0;
+ for (i = 0; i < MAK; i++)
+ r += arr[i];
+ return r;
+}
+
diff --git a/gcc/testsuite/g++.dg/ext/attr-aligned01.C b/gcc/testsuite/g++.dg/ext/attr-aligned01.C
index c8ec07d..0c5df6d 100644
--- a/gcc/testsuite/g++.dg/ext/attr-aligned01.C
+++ b/gcc/testsuite/g++.dg/ext/attr-aligned01.C
@@ -5,8 +5,8 @@
template<typename T>
void type_alignment(const T&) {
- struct { char c; T t; } s;
- SA((char*)&s.t - (char*)&s.c == 1);
+ struct S { char c; T t; } s;
+ SA(__builtin_offsetof (S,t) - __builtin_offsetof (S,c) == 1);
}
template <class T> struct A { char c; T t; };
@@ -17,7 +17,8 @@ int main() {
A<aligned> a; // { dg-warning "ignoring attributes" }
- SA((char*)&a.t - (char*)&a.c == 1);
+ SA( __builtin_offsetof (__typeof(a),t)
+ - __builtin_offsetof (__typeof(a),c) == 1);
aligned z;
type_alignment(z); // { dg-warning "ignoring attributes" "" { xfail *-*-* } }
diff --git a/gcc/testsuite/g++.dg/ext/offsetof1.C b/gcc/testsuite/g++.dg/ext/offsetof1.C
index 1468c0a..23f3537 100644
--- a/gcc/testsuite/g++.dg/ext/offsetof1.C
+++ b/gcc/testsuite/g++.dg/ext/offsetof1.C
@@ -1,6 +1,7 @@
// PR c++/27601
// Origin: Patrik Hägglund <patrik.hagglund@bredband.net>
// { dg-do compile }
+// { dg-options "-Wno-pointer-arith" }
struct bar {
static int foo;
@@ -10,7 +11,7 @@ struct bar {
int a = __builtin_offsetof(bar, foo); // { dg-error "static data member" }
int av = __builtin_offsetof(volatile bar, foo); // { dg-error "static data member" }
int b = __builtin_offsetof(bar, baz); // { dg-error "member function" }
-int b0 = __builtin_offsetof(bar, baz[0]); // { dg-error "function" }
+int b0 = __builtin_offsetof(bar, baz[0]); // { dg-error "single identifier nor|member function" }
int bv0 = __builtin_offsetof(volatile bar, baz[0]); // { dg-error "function" }
int c = __builtin_offsetof(bar, ~bar); // { dg-error "member function" }
diff --git a/gcc/testsuite/g++.dg/init/const7.C b/gcc/testsuite/g++.dg/init/const7.C
index dbc60b3..e1f31bc 100644
--- a/gcc/testsuite/g++.dg/init/const7.C
+++ b/gcc/testsuite/g++.dg/init/const7.C
@@ -1,9 +1,9 @@
// { dg-do compile }
-// { dg-options "-fdump-tree-gimple" }
+// { dg-options "-fdump-tree-gimple -pedantic" }
struct s { int x, y; };
short offsets[1] = {
- ((char*) &(((struct s*)16)->y) - (char *)16),
+ ((char*) &(((struct s*)16)->y) - (char *)16), // { dg-message "narrowing" "" { target c++11 } }
};
// This ensures that we get a dump whether or not the bug is present.
diff --git a/gcc/testsuite/g++.dg/init/self1.C b/gcc/testsuite/g++.dg/init/self1.C
index dd37c8e..7620833 100644
--- a/gcc/testsuite/g++.dg/init/self1.C
+++ b/gcc/testsuite/g++.dg/init/self1.C
@@ -10,7 +10,7 @@ void f(__SIZE_TYPE__) {
int main()
{
- int* const savepos = sizeof(*savepos) ? 0 : 0;
+ int* const savepos = sizeof(*savepos) ? 0 : 0; /* { dg-error "invalid conversion" "convert" { target c++11 } } */
f (sizeof (*savepos));
diff --git a/gcc/testsuite/g++.dg/other/error22.C b/gcc/testsuite/g++.dg/other/error22.C
index 225dcae..eba0746 100644
--- a/gcc/testsuite/g++.dg/other/error22.C
+++ b/gcc/testsuite/g++.dg/other/error22.C
@@ -5,5 +5,5 @@ extern "C" double fabs (double);
void foo (double x)
{
- fabs (x) (); // { dg-error "__builtin_abs" }
+ fabs (x) (); // { dg-error "function" }
}
diff --git a/gcc/testsuite/g++.dg/other/error24.C b/gcc/testsuite/g++.dg/other/error24.C
index 54343c5..e5e6a4f 100644
--- a/gcc/testsuite/g++.dg/other/error24.C
+++ b/gcc/testsuite/g++.dg/other/error24.C
@@ -8,6 +8,6 @@ void
bar (int i, int j, double k)
{
foo (i && j) (); // { dg-error "\\(\\(?i != 0\\)? \\&\\& \\(?j != 0\\)?\\)" }
- foo (!i || !j) (); // { dg-error "\\(\\(?i == 0\\)? \\|\\| \\(?j == 0\\)?\\)" }
- foo (!i == !j) (); // { dg-error "\\(\\(?i != 0\\)? \\^ \\(?j == 0\\)?\\)" }
+ foo (!i || !j) (); // { dg-error "function" }
+ foo (!i == !j) (); // { dg-error "function" }
}
diff --git a/gcc/testsuite/g++.dg/other/error26.C b/gcc/testsuite/g++.dg/other/error26.C
index fb2c8b7..ffe2728 100644
--- a/gcc/testsuite/g++.dg/other/error26.C
+++ b/gcc/testsuite/g++.dg/other/error26.C
@@ -2,5 +2,5 @@
void foo(__complex__ double x)
{
- __builtin_conj(x)(); // { dg-error "~x" }
+ __builtin_conj(x)(); // { dg-error "function" }
}
diff --git a/gcc/testsuite/g++.dg/parse/array-size2.C b/gcc/testsuite/g++.dg/parse/array-size2.C
index 355ed61..3c83347 100644
--- a/gcc/testsuite/g++.dg/parse/array-size2.C
+++ b/gcc/testsuite/g++.dg/parse/array-size2.C
@@ -14,7 +14,7 @@ extern void bar (char *, char *);
void
foo (void)
{
- char g[(char *) &((struct S *) 0)->b - (char *) 0];
- char h[(__SIZE_TYPE__) &((struct S *) 8)->b];
+ char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" }
+ char h[(__SIZE_TYPE__) &((struct S *) 8)->b]; // { dg-error "constant" "" { xfail *-*-* } }
bar (g, h);
}
diff --git a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
index 946f2e6..8014705 100644
--- a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
@@ -1,14 +1,10 @@
/* { dg-do compile } */
/* { dg-options "-fsanitize=integer-divide-by-zero" } */
-/* TODO: We expect an error on the invalid case here, because that
- must be a constant-expression. This will be fixed when we have
- proper delayed folding. */
-
void
foo (int i)
{
switch (i)
case 0 * (1 / 0): /* { dg-warning "division by zero" } */
- ; /* { dg-error "division by zero" "" { xfail *-*-* } 10 } */
+ ; /* { dg-error "is not a constant.expression" "" { target *-*-* } 8 } */
}
diff --git a/gcc/testsuite/g++.dg/ubsan/shift-1.C b/gcc/testsuite/g++.dg/ubsan/shift-1.C
index 05e049e..493a55c 100644
--- a/gcc/testsuite/g++.dg/ubsan/shift-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/shift-1.C
@@ -8,10 +8,10 @@ foo (int x)
/* None of the following should pass. */
switch (x)
{
- case 1 >> -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
- case -1 >> -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
- case 1 << -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
- case -1 << -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
+ case 1 >> -1: /* { dg-error "operand of shift" "" } */
+ case -1 >> -1: /* { dg-error "operand of shift" "" } */
+ case 1 << -1: /* { dg-error "operand of shift" "" } */
+ case -1 << -1: /* { dg-error "operand of shift" "" } */
return 1;
}
return 0;
@@ -23,8 +23,8 @@ bar (int x)
/* None of the following should pass. */
switch (x)
{
- case -1 >> 200: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
- case 1 << 200: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
+ case -1 >> 200: /* { dg-error "operand of shift" "" } */
+ case 1 << 200: /* { dg-error "operand of shift" "" } */
return 1;
}
return 0;
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
index 7cd76e7..a10e15b 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
@@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
- /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+ /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */
/* Again, overflow in evaluated subexpression. */
@@ -126,3 +126,11 @@ h2i (int x)
ui = INT_MIN;
ui = x ? INT_MIN : 1U;
}
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 32 } */
+/* { dg-warning "invalid conversion from" "convert" { target *-*-* } 56 } */
+/* { dg-warning "invalid conversion from" "convert" { target c++11 } 58 } */
+/* { dg-error "is not a constant expression" "const" { target *-*-* } 65 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 65 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 32 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 32 } */
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
index 73c0e00..c73a28c 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
@@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
- /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+ /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */
/* Again, overflow in evaluated subexpression. */
@@ -56,7 +56,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" }
/* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* } 55 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-warning "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 58 } */
+/* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */
void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
void
@@ -65,7 +65,7 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
- ;
+ ; /* { dg-error "is not a constant expression" "const" { target *-*-* } 67 } */
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 69 } */
;
@@ -128,3 +128,9 @@ h2i (int x)
ui = INT_MIN;
ui = x ? INT_MIN : 1U;
}
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 32 } */
+/* { dg-warning "invalid conversion from" "convert" { target c++11 } 60 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 67 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 32 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 32 } */
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
index 24b3959..23a2585 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
@@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
- /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+ /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
/* { dg-error "enumerator value for 'E5' is not an integer constant" "enum error" { target *-*-* } 21 } */
@@ -59,7 +59,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" }
/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 61 } */
+/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 61 } */
void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
void
@@ -68,7 +68,7 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
- ;
+ ; /* { dg-error "is not a constant expression" "const" { target *-*-* } 70 } */
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 72 } */
;
@@ -131,3 +131,9 @@ h2i (int x)
ui = INT_MIN;
ui = x ? INT_MIN : 1U;
}
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "invalid conversion from" "convert" { target c++11 } 63 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 34 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 70 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 34 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 34 } */
diff --git a/gcc/testsuite/g++.old-deja/g++.other/null3.C b/gcc/testsuite/g++.old-deja/g++.other/null3.C
index ff1d0669..96691d3 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/null3.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/null3.C
@@ -3,5 +3,5 @@
void x()
{
int* p = 1==0; // { dg-warning "converting 'false' to pointer" "" { target { ! c++11 } } }
-// { dg-error "cannot convert" "" { target c++11 } 5 }
+// { dg-error "cannot convert" "" { target { c++11 } } 5 }
}
diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c
index 11d5999..0204cfe 100644
--- a/gcc/tree-complex.c
+++ b/gcc/tree-complex.c
@@ -432,8 +432,8 @@ create_one_component_var (tree type, tree orig, const char *prefix,
if (DECL_NAME (orig) && !DECL_IGNORED_P (orig))
{
const char *name = IDENTIFIER_POINTER (DECL_NAME (orig));
-
- DECL_NAME (r) = get_identifier (ACONCAT ((name, suffix, NULL)));
+ name = ACONCAT ((name, suffix, NULL));
+ DECL_NAME (r) = get_identifier (name);
SET_DECL_DEBUG_EXPR (r, build1 (code, type, orig));
DECL_HAS_DEBUG_EXPR_P (r) = 1;
commit 2689ad9313b746c46a952bdec5f214ec737bc12e
Author: Jason Merrill <jason@redhat.com>
Date: Mon Nov 9 01:14:35 2015 -0500
Merge c++-delayed-folding branch.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 0b7d143..536989b 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4747,7 +4747,7 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
tree cmp_type = build_same_sized_truth_vector_type (arg1_type);
arg1 = build2 (NE_EXPR, cmp_type, arg1, build_zero_cst (arg1_type));
}
- return fold_build3 (VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
+ return build3_loc (loc, VEC_COND_EXPR, arg2_type, arg1, arg2, arg3);
}
/* [expr.cond]
@@ -5151,9 +5151,6 @@ build_conditional_expr_1 (location_t loc, tree arg1, tree arg2, tree arg3,
valid_operands:
result = build3_loc (loc, COND_EXPR, result_type, arg1, arg2, arg3);
- if (!cp_unevaluated_operand)
- /* Avoid folding within decltype (c++/42013) and noexcept. */
- result = fold_if_not_in_template (result);
/* We can't use result_type below, as fold might have returned a
throw_expr. */
@@ -5689,8 +5686,8 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
decaying an enumerator to its value. */
if (complain & tf_warning)
warn_logical_operator (loc, code, boolean_type_node,
- code_orig_arg1, arg1,
- code_orig_arg2, arg2);
+ code_orig_arg1, fold (arg1),
+ code_orig_arg2, fold (arg2));
arg2 = convert_like (conv, arg2, complain);
}
@@ -5728,7 +5725,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
case TRUTH_OR_EXPR:
if (complain & tf_warning)
warn_logical_operator (loc, code, boolean_type_node,
- code_orig_arg1, arg1, code_orig_arg2, arg2);
+ code_orig_arg1, fold (arg1), code_orig_arg2, fold (arg2));
/* Fall through. */
case GT_EXPR:
case LT_EXPR:
@@ -5739,9 +5736,10 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1,
if ((complain & tf_warning)
&& ((code_orig_arg1 == BOOLEAN_TYPE)
^ (code_orig_arg2 == BOOLEAN_TYPE)))
- maybe_warn_bool_compare (loc, code, arg1, arg2);
+ maybe_warn_bool_compare (loc, code, fold (arg1),
+ fold (arg2));
if (complain & tf_warning && warn_tautological_compare)
- warn_tautological_cmp (loc, code, arg1, arg2);
+ warn_tautological_cmp (loc, code, fold (arg1), fold (arg2));
/* Fall through. */
case PLUS_EXPR:
case MINUS_EXPR:
@@ -6495,7 +6493,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
imag = perform_implicit_conversion (TREE_TYPE (totype),
imag, complain);
expr = build2 (COMPLEX_EXPR, totype, real, imag);
- return fold_if_not_in_template (expr);
+ return expr;
}
expr = reshape_init (totype, expr, complain);
expr = get_target_expr_sfinae (digest_init (totype, expr, complain),
@@ -6736,7 +6734,7 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
"implicit conversion from %qT to %qT when passing "
"argument to function",
arg_type, double_type_node);
- arg = convert_to_real (double_type_node, arg);
+ arg = convert_to_real_nofold (double_type_node, arg);
}
else if (NULLPTR_TYPE_P (arg_type))
arg = null_pointer_node;
@@ -6981,7 +6979,7 @@ convert_for_arg_passing (tree type, tree val, tsubst_flags_t complain)
bitfield_type = is_bitfield_expr_with_lowered_type (val);
if (bitfield_type
&& TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type))
- val = convert_to_integer (TYPE_MAIN_VARIANT (bitfield_type), val);
+ val = convert_to_integer_nofold (TYPE_MAIN_VARIANT (bitfield_type), val);
if (val == error_mark_node)
;
@@ -7501,7 +7499,19 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
gcc_assert (j <= nargs);
nargs = j;
- check_function_arguments (TREE_TYPE (fn), nargs, argarray);
+ /* Avoid to do argument-transformation, if warnings for format, and for
+ nonnull are disabled. Just in case that at least one of them is active
+ the check_function_arguments function might warn about something. */
+
+ if (warn_nonnull || warn_format || warn_suggest_attribute_format)
+ {
+ tree *fargs = (!nargs ? argarray
+ : (tree *) alloca (nargs * sizeof (tree)));
+ for (j = 0; j < nargs; j++)
+ fargs[j] = maybe_constant_value (argarray[j]);
+
+ check_function_arguments (TREE_TYPE (fn), nargs, fargs);
+ }
/* Avoid actually calling copy constructors and copy assignment operators,
if possible. */
@@ -7692,7 +7702,6 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
tsubst_flags_t complain)
{
tree fndecl;
- int optimize_sav;
/* Remember roughly where this call is. */
location_t loc = EXPR_LOC_OR_LOC (fn, input_location);
@@ -7704,9 +7713,18 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
/* Check that arguments to builtin functions match the expectations. */
if (fndecl
&& DECL_BUILT_IN (fndecl)
- && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
- && !check_builtin_function_arguments (fndecl, nargs, argarray))
- return error_mark_node;
+ && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+ {
+ int i;
+
+ /* We need to take care that values to BUILT_IN_NORMAL
+ are reduced. */
+ for (i = 0; i < nargs; i++)
+ argarray[i] = maybe_constant_value (argarray[i]);
+
+ if (!check_builtin_function_arguments (fndecl, nargs, argarray))
+ return error_mark_node;
+ }
/* If it is a built-in array notation function, then the return type of
the function is the element type of the array passed in as array
@@ -7740,17 +7758,6 @@ build_cxx_call (tree fn, int nargs, tree *argarray,
}
}
- /* Some built-in function calls will be evaluated at compile-time in
- fold (). Set optimize to 1 when folding __builtin_constant_p inside
- a constexpr function so that fold_builtin_1 doesn't fold it to 0. */
- optimize_sav = optimize;
- if (!optimize && fndecl && DECL_IS_BUILTIN_CONSTANT_P (fndecl)
- && current_function_decl
- && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
- optimize = 1;
- fn = fold_if_not_in_template (fn);
- optimize = optimize_sav;
-
if (VOID_TYPE_P (TREE_TYPE (fn)))
return fn;
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index b123932..b5cf996 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -423,7 +423,7 @@ build_base_path (enum tree_code code,
t = TREE_TYPE (TYPE_VFIELD (current_class_type));
t = build_pointer_type (t);
- v_offset = convert (t, current_vtt_parm);
+ v_offset = fold_convert (t, current_vtt_parm);
v_offset = cp_build_indirect_ref (v_offset, RO_NULL, complain);
}
else
@@ -556,8 +556,6 @@ build_simple_base_path (tree expr, tree binfo)
expr = build3 (COMPONENT_REF,
cp_build_qualified_type (type, type_quals),
expr, field, NULL_TREE);
- expr = fold_if_not_in_template (expr);
-
/* Mark the expression const or volatile, as appropriate.
Even though we've dealt with the type above, we still have
to mark the expression itself. */
@@ -1849,9 +1847,9 @@ determine_primary_bases (tree t)
another hierarchy. As we're about to use it as a
primary base, make sure the offsets match. */
delta = size_diffop_loc (input_location,
- convert (ssizetype,
+ fold_convert (ssizetype,
BINFO_OFFSET (base_binfo)),
- convert (ssizetype,
+ fold_convert (ssizetype,
BINFO_OFFSET (this_primary)));
propagate_binfo_offsets (this_primary, delta);
@@ -1913,7 +1911,7 @@ determine_primary_bases (tree t)
another hierarchy. As we're about to use it as a primary
base, make sure the offsets match. */
delta = size_diffop_loc (input_location, ssize_int (0),
- convert (ssizetype, BINFO_OFFSET (primary)));
+ fold_convert (ssizetype, BINFO_OFFSET (primary)));
propagate_binfo_offsets (primary, delta);
}
@@ -2637,7 +2635,7 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
if (virtual_offset
|| (thunk_binfo && !BINFO_OFFSET_ZEROP (thunk_binfo)))
{
- tree offset = convert (ssizetype, BINFO_OFFSET (thunk_binfo));
+ tree offset = fold_convert (ssizetype, BINFO_OFFSET (thunk_binfo));
if (virtual_offset)
{
@@ -2645,7 +2643,7 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
offset to be from there. */
offset =
size_diffop (offset,
- convert (ssizetype,
+ fold_convert (ssizetype,
BINFO_OFFSET (virtual_offset)));
}
if (fixed_offset)
@@ -2734,8 +2732,8 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
/* The `this' pointer needs to be adjusted from the declaration to
the nearest virtual base. */
delta = size_diffop_loc (input_location,
- convert (ssizetype, BINFO_OFFSET (virtual_base)),
- convert (ssizetype, BINFO_OFFSET (first_defn)));
+ fold_convert (ssizetype, BINFO_OFFSET (virtual_base)),
+ fold_convert (ssizetype, BINFO_OFFSET (first_defn)));
else if (lost)
/* If the nearest definition is in a lost primary, we don't need an
entry in our vtable. Except possibly in a constructor vtable,
@@ -2747,9 +2745,9 @@ update_vtable_entry_for_fn (tree t, tree binfo, tree fn, tree* virtuals,
BINFO to pointing at the base where the final overrider
appears. */
delta = size_diffop_loc (input_location,
- convert (ssizetype,
+ fold_convert (ssizetype,
BINFO_OFFSET (TREE_VALUE (overrider))),
- convert (ssizetype, BINFO_OFFSET (binfo)));
+ fold_convert (ssizetype, BINFO_OFFSET (binfo)));
modify_vtable_entry (t, binfo, overrider_fn, delta, virtuals);
@@ -3471,7 +3469,7 @@ check_bitfield_decl (tree field)
if (w != error_mark_node)
{
- DECL_SIZE (field) = convert (bitsizetype, w);
+ DECL_SIZE (field) = fold_convert (bitsizetype, w);
DECL_BIT_FIELD (field) = 1;
return true;
}
@@ -4316,8 +4314,8 @@ layout_nonempty_base_or_field (record_layout_info rli,
OFFSET. */
propagate_binfo_offsets (binfo,
size_diffop_loc (input_location,
- convert (ssizetype, offset),
- convert (ssizetype,
+ fold_convert (ssizetype, offset),
+ fold_convert (ssizetype,
BINFO_OFFSET (binfo))));
}
@@ -4364,7 +4362,7 @@ layout_empty_base (record_layout_info rli, tree binfo,
/* That didn't work. Now, we move forward from the next
available spot in the class. */
atend = true;
- propagate_binfo_offsets (binfo, convert (ssizetype, eoc));
+ propagate_binfo_offsets (binfo, fold_convert (ssizetype, eoc));
while (1)
{
if (!layout_conflict_p (binfo,
@@ -5978,9 +5976,9 @@ propagate_binfo_offsets (tree binfo, tree offset)
/* Update BINFO's offset. */
BINFO_OFFSET (binfo)
- = convert (sizetype,
+ = fold_convert (sizetype,
size_binop (PLUS_EXPR,
- convert (ssizetype, BINFO_OFFSET (binfo)),
+ fold_convert (ssizetype, BINFO_OFFSET (binfo)),
offset));
/* Find the primary base class. */
@@ -6185,7 +6183,7 @@ include_empty_classes (record_layout_info rli)
= size_binop (PLUS_EXPR,
rli->bitpos,
size_binop (MULT_EXPR,
- convert (bitsizetype,
+ fold_convert (bitsizetype,
size_binop (MINUS_EXPR,
eoc, rli_size)),
bitsize_int (BITS_PER_UNIT)));
@@ -6459,7 +6457,7 @@ layout_class_type (tree t, tree *virtuals_p)
eoc = end_of_class (t, /*include_virtuals_p=*/0);
TYPE_SIZE_UNIT (base_t)
= size_binop (MAX_EXPR,
- convert (sizetype,
+ fold_convert (sizetype,
size_binop (CEIL_DIV_EXPR,
rli_size_so_far (rli),
bitsize_int (BITS_PER_UNIT))),
@@ -6468,7 +6466,7 @@ layout_class_type (tree t, tree *virtuals_p)
= size_binop (MAX_EXPR,
rli_size_so_far (rli),
size_binop (MULT_EXPR,
- convert (bitsizetype, eoc),
+ fold_convert (bitsizetype, eoc),
bitsize_int (BITS_PER_UNIT)));
TYPE_ALIGN (base_t) = rli->record_align;
TYPE_USER_ALIGN (base_t) = TYPE_USER_ALIGN (t);
@@ -9304,7 +9302,7 @@ build_vbase_offset_vtbl_entries (tree binfo, vtbl_init_data* vid)
/* Figure out where we can find this vbase offset. */
delta = size_binop (MULT_EXPR,
vid->index,
- convert (ssizetype,
+ fold_convert (ssizetype,
TYPE_SIZE_UNIT (vtable_entry_type)));
if (vid->primary_vtbl_p)
BINFO_VPTR_FIELD (b) = delta;
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 51fae5a..5bda494 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -1037,6 +1037,8 @@ cxx_eval_builtin_function_call (const constexpr_ctx *ctx, tree t, tree fun,
force_folding_builtin_constant_p = true;
new_call = fold_build_call_array_loc (EXPR_LOCATION (t), TREE_TYPE (t),
CALL_EXPR_FN (t), nargs, args);
+ /* Fold away the NOP_EXPR from fold_builtin_n. */
+ new_call = fold (new_call);
force_folding_builtin_constant_p = save_ffbcp;
VERIFY_CONSTANT (new_call);
return new_call;
@@ -1277,6 +1279,15 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t,
ctx->values->put (new_ctx.object, ctor);
ctx = &new_ctx;
}
+ else if (DECL_BY_REFERENCE (DECL_RESULT (fun))
+ && TREE_CODE (t) != AGGR_INIT_EXPR)
+ {
+ /* convert_to_void stripped our AGGR_INIT_EXPR, in which case we don't
+ care about a constant value. */
+ gcc_assert (ctx->quiet && !ctx->object);
+ *non_constant_p = true;
+ return t;
+ }
bool non_constant_args = false;
cxx_bind_parameters_in_call (ctx, t, &new_call,
@@ -2542,6 +2553,17 @@ cxx_eval_indirect_ref (const constexpr_ctx *ctx, tree t,
tree orig_op0 = TREE_OPERAND (t, 0);
bool empty_base = false;
+ /* We can handle a MEM_REF like an INDIRECT_REF, if MEM_REF's second
+ operand is an integer-zero. Otherwise reject the MEM_REF for now. */
+
+ if (TREE_CODE (t) == MEM_REF
+ && (!TREE_OPERAND (t, 1) || !integer_zerop (TREE_OPERAND (t, 1))))
+ {
+ gcc_assert (ctx->quiet);
+ *non_constant_p = true;
+ return t;
+ }
+
/* First try to simplify it directly. */
tree r = cxx_fold_indirect_ref (EXPR_LOCATION (t), TREE_TYPE (t), orig_op0,
&empty_base);
@@ -3075,6 +3097,8 @@ cxx_eval_pointer_plus_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CODE (op00) != ADDR_EXPR)
return NULL_TREE;
+ op01 = cxx_eval_constant_expression (ctx, op01, lval,
+ non_constant_p, overflow_p);
op00 = TREE_OPERAND (op00, 0);
/* &A[i] p+ j => &A[i + j] */
@@ -3335,6 +3359,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
/* 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 MEM_REF:
case INDIRECT_REF:
r = cxx_eval_indirect_ref (ctx, t, lval,
non_constant_p, overflow_p);
@@ -3540,8 +3565,11 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
case CONVERT_EXPR:
case VIEW_CONVERT_EXPR:
case NOP_EXPR:
+ case UNARY_PLUS_EXPR:
{
+ enum tree_code tcode = TREE_CODE (t);
tree oldop = TREE_OPERAND (t, 0);
+
tree op = cxx_eval_constant_expression (ctx, oldop,
lval,
non_constant_p, overflow_p);
@@ -3561,11 +3589,14 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
*non_constant_p = true;
return t;
}
- if (op == oldop)
+ if (op == oldop && tcode != UNARY_PLUS_EXPR)
/* We didn't fold at the top so we could check for ptr-int
conversion. */
return fold (t);
- r = fold_build1 (TREE_CODE (t), type, op);
+ if (tcode == UNARY_PLUS_EXPR)
+ r = fold_convert (TREE_TYPE (t), op);
+ else
+ r = fold_build1 (tcode, type, op);
/* Conversion of an out-of-range value has implementation-defined
behavior; the language considers it different from arithmetic
overflow, which is undefined. */
@@ -3833,12 +3864,187 @@ cxx_constant_value (tree t, tree decl)
return cxx_eval_outermost_constant_expr (t, false, true, decl);
}
+/* Helper routine for fold_simple function. Either return simplified
+ expression T, otherwise NULL_TREE.
+ In contrast to cp_fully_fold, and to maybe_constant_value, we try to fold
+ even if we are within template-declaration. So be careful on call, as in
+ such case types can be undefined. */
+
+static tree
+fold_simple_1 (tree t)
+{
+ tree op1, op2, op3;
+ enum tree_code code = TREE_CODE (t);
+
+ if (code == VAR_DECL)
+ return NULL_TREE;
+
+ switch (code)
+ {
+ case INTEGER_CST:
+ case REAL_CST:
+ case VECTOR_CST:
+ case FIXED_CST:
+ case COMPLEX_CST:
+ return t;
+
+ case SIZEOF_EXPR:
+ if (SIZEOF_EXPR_TYPE_P (t))
+ t = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (t, 0)),
+ SIZEOF_EXPR, false);
+ else if (TYPE_P (TREE_OPERAND (t, 0)))
+ t = cxx_sizeof_or_alignof_type (TREE_OPERAND (t, 0),
+ SIZEOF_EXPR, false);
+ else
+ t = cxx_sizeof_or_alignof_expr (TREE_OPERAND (t, 0),
+ SIZEOF_EXPR, false);
+ if (t == error_mark_node)
+ t = size_one_node;
+ break;
+
+ case ABS_EXPR:
+ case CONJ_EXPR:
+ case REALPART_EXPR:
+ case IMAGPART_EXPR:
+ case NEGATE_EXPR:
+ case BIT_NOT_EXPR:
+ case TRUTH_NOT_EXPR:
+ case NOP_EXPR:
+ case VIEW_CONVERT_EXPR:
+ case CONVERT_EXPR:
+ case FLOAT_EXPR:
+ case FIX_TRUNC_EXPR:
+ case FIXED_CONVERT_EXPR:
+ case ADDR_SPACE_CONVERT_EXPR:
+
+ op1 = fold_simple_1 (TREE_OPERAND (t, 0));
+ if (!op1 || (code == NOP_EXPR && TREE_OVERFLOW (op1)))
+ return NULL_TREE;
+
+ t = const_unop (code, TREE_TYPE (t), op1);
+ if (!t)
+ return NULL_TREE;
+
+ if (CONVERT_EXPR_CODE_P (code)
+ && TREE_OVERFLOW_P (t) && !TREE_OVERFLOW_P (op1))
+ TREE_OVERFLOW (t) = false;
+ break;
+
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_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 TRUTH_AND_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_ORIF_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:
+
+ op1 = fold_simple_1 (TREE_OPERAND (t, 0));
+ op2 = fold_simple_1 (TREE_OPERAND (t, 1));
+
+ if (!op1 && !op2)
+ return NULL_TREE;
+ if (!op1)
+ op1 = TREE_OPERAND (t, 0);
+ if (!op2)
+ op2 = TREE_OPERAND (t, 1);
+
+ t = fold_build2_loc (EXPR_LOCATION (t), code, TREE_TYPE (t),
+ op1, op2);
+ break;
+
+ case VEC_COND_EXPR:
+ case COND_EXPR:
+
+ if (VOID_TYPE_P (TREE_TYPE (t)))
+ return NULL_TREE;
+
+ op1 = TREE_OPERAND (t, 0);
+ op1 = fold_simple_1 (op1);
+ op2 = TREE_OPERAND (t, 1);
+ op3 = TREE_OPERAND (t, 2);
+ if (!op1)
+ return NULL_TREE;
+ op1 = fold (build3 (code, TREE_TYPE (t), op1, op2, op3));
+
+ /* We need to recurse into result, if CODE isn't
+ a COND-expression. */
+ if (TREE_CODE (op1) != code)
+ return fold_simple_1 (op1);
+ return NULL_TREE;
+
+ default:
+ return NULL_TREE;
+ }
+
+ /* Just return folded expression if we got as result
+ a CST-expression. */
+ switch (TREE_CODE (t))
+ {
+ case STRING_CST:
+ case INTEGER_CST:
+ case REAL_CST:
+ case VECTOR_CST:
+ case FIXED_CST:
+ case COMPLEX_CST:
+ break;
+ default:
+ return NULL_TREE;
+ }
+
+ return t;
+}
+
+/* If T is a simple constant expression, returns its simplified value.
+ Otherwise returns T. In contrast to maybe_constant_value do we
+ simplify only few operations on constant-expressions, and we don't
+ try to simplify constexpressions. */
+
+tree
+fold_simple (tree t)
+{
+ tree r = NULL_TREE;
+ if (processing_template_decl)
+ return t;
+
+ r = fold_simple_1 (t);
+ if (!r)
+ r = t;
+
+ return r;
+}
+
/* 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 decl)
+static tree
+maybe_constant_value_1 (tree t, tree decl)
{
tree r;
@@ -3864,6 +4070,56 @@ maybe_constant_value (tree t, tree decl)
return r;
}
+/* 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 decl)
+{
+ tree ret;
+ hash_map<tree, tree> *ctx = (scope_chain ? scope_chain->fold_map : NULL);
+ hash_map<tree, tree> *cv = (scope_chain ? scope_chain->cv_map : NULL);
+
+ /* If current scope has a hash_map, but it was for different CFUN,
+ then destroy hash_map to avoid issues with ggc_collect. */
+ if ((cv || ctx) && scope_chain->act_cfun != cfun)
+ {
+ if (ctx)
+ delete ctx;
+ if (cv)
+ delete cv;
+ ctx = NULL;
+ scope_chain->act_cfun = NULL;
+ scope_chain->fold_map = NULL;
+ scope_chain->cv_map = NULL;
+ }
+ if (cv && scope_chain && cfun)
+ {
+ cv = scope_chain->cv_map = new hash_map <tree, tree>;
+ scope_chain->act_cfun = cfun;
+ }
+
+ if (cv)
+ {
+ tree *slot = cv->get (t);
+ if (slot && *slot)
+ return *slot;
+ }
+
+ ret = maybe_constant_value_1 (t, decl);
+
+ if (cv)
+ {
+ /* We don't need to cache RET, as it is a
+ constant-value if it differs. */
+ tree *slot = &cv->get_or_insert (t);
+ *slot = ret;
+ }
+
+ return ret;
+}
+
/* Like maybe_constant_value but first fully instantiate the argument.
Note: this is equivalent to instantiate_non_dependent_expr_sfinae
@@ -3929,6 +4185,8 @@ fold_non_dependent_expr (tree t)
tree
maybe_constant_init (tree t, tree decl)
{
+ if (!t)
+ return t;
if (TREE_CODE (t) == EXPR_STMT)
t = TREE_OPERAND (t, 0);
if (TREE_CODE (t) == CONVERT_EXPR
@@ -4039,6 +4297,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
/* We can see a FIELD_DECL in a pointer-to-member expression. */
case FIELD_DECL:
case PARM_DECL:
+ case RESULT_DECL:
case USING_DECL:
case USING_STMT:
case PLACEHOLDER_EXPR:
@@ -4627,6 +4886,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
/* We can see these in statement-expressions. */
return true;
+ case EMPTY_CLASS_EXPR:
+ return false;
+
default:
if (objc_is_property_ref (t))
return false;
diff --git a/gcc/cp/cp-array-notation.c b/gcc/cp/cp-array-notation.c
index 9fd348c..e967c72 100644
--- a/gcc/cp/cp-array-notation.c
+++ b/gcc/cp/cp-array-notation.c
@@ -1382,7 +1382,12 @@ build_array_notation_ref (location_t loc, tree array, tree start, tree length,
if (!stride)
stride = build_one_cst (ptrdiff_type_node);
-
+
+ stride = maybe_constant_value (stride);
+ length = maybe_constant_value (length);
+ if (start)
+ start = maybe_constant_value (start);
+
/* When dealing with templates, triplet type-checking will be done in pt.c
after type substitution. */
if (processing_template_decl
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index e4b50e5..c14ddce 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -41,7 +41,9 @@ along with GCC; see the file COPYING3. If not see
/* Forward declarations. */
static tree cp_genericize_r (tree *, int *, void *);
+static tree cp_fold_r (tree *, int *, void *);
static void cp_genericize_tree (tree*);
+static tree cp_fold (tree, hash_map<tree, tree> *);
/* Local declarations. */
@@ -181,13 +183,13 @@ genericize_eh_spec_block (tree *stmt_p)
/* Genericize an IF_STMT by turning it into a COND_EXPR. */
static void
-genericize_if_stmt (tree *stmt_p)
+genericize_if_stmt (tree *stmt_p, hash_map<tree, tree> *fold_hash)
{
tree stmt, cond, then_, else_;
location_t locus = EXPR_LOCATION (*stmt_p);
stmt = *stmt_p;
- cond = IF_COND (stmt);
+ cond = cp_fold (IF_COND (stmt), fold_hash);
then_ = THEN_CLAUSE (stmt);
else_ = ELSE_CLAUSE (stmt);
@@ -916,9 +918,76 @@ struct cp_genericize_data
vec<tree> bind_expr_stack;
struct cp_genericize_omp_taskreg *omp_ctx;
tree try_block;
+ hash_map<tree, tree> *fold_hash;
bool no_sanitize_p;
};
+/* Perform any pre-gimplification folding of C++ front end trees to
+ GENERIC.
+ Note: The folding of none-omp cases is something to move into
+ the middle-end. As for now we have most foldings only on GENERIC
+ in fold-const, we need to perform this before transformation to
+ GIMPLE-form. */
+
+static tree
+cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data)
+{
+ tree stmt;
+ struct cp_genericize_data *wtd = (struct cp_genericize_data *) data;
+ enum tree_code code;
+
+ *stmt_p = stmt = cp_fold (*stmt_p, wtd->fold_hash);
+
+ code = TREE_CODE (stmt);
+ if (code == OMP_FOR || code == OMP_SIMD || code == OMP_DISTRIBUTE
+ || code == OMP_TASKLOOP || code == CILK_FOR || code == CILK_SIMD)
+ {
+ tree x;
+ int i, n;
+
+ cp_walk_tree (&OMP_FOR_BODY (stmt), cp_fold_r, data, NULL);
+ cp_walk_tree (&OMP_FOR_CLAUSES (stmt), cp_fold_r, data, NULL);
+ cp_walk_tree (&OMP_FOR_INIT (stmt), cp_fold_r, data, NULL);
+ x = OMP_FOR_COND (stmt);
+ if (x && TREE_CODE_CLASS (TREE_CODE (x)) == tcc_comparison)
+ {
+ cp_walk_tree (&TREE_OPERAND (x, 0), cp_fold_r, data, NULL);
+ cp_walk_tree (&TREE_OPERAND (x, 1), cp_fold_r, data, NULL);
+ }
+ else if (x && TREE_CODE (x) == TREE_VEC)
+ {
+ n = TREE_VEC_LENGTH (x);
+ for (i = 0; i < n; i++)
+ {
+ tree o = TREE_VEC_ELT (x, i);
+ if (o && TREE_CODE_CLASS (TREE_CODE (o)) == tcc_comparison)
+ cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL);
+ }
+ }
+ x = OMP_FOR_INCR (stmt);
+ if (x && TREE_CODE (x) == TREE_VEC)
+ {
+ n = TREE_VEC_LENGTH (x);
+ for (i = 0; i < n; i++)
+ {
+ tree o = TREE_VEC_ELT (x, i);
+ if (o && TREE_CODE (o) == MODIFY_EXPR)
+ o = TREE_OPERAND (o, 1);
+ if (o && (TREE_CODE (o) == PLUS_EXPR || TREE_CODE (o) == MINUS_EXPR
+ || TREE_CODE (o) == POINTER_PLUS_EXPR))
+ {
+ cp_walk_tree (&TREE_OPERAND (o, 0), cp_fold_r, data, NULL);
+ cp_walk_tree (&TREE_OPERAND (o, 1), cp_fold_r, data, NULL);
+ }
+ }
+ }
+ cp_walk_tree (&OMP_FOR_PRE_BODY (stmt), cp_fold_r, data, NULL);
+ *walk_subtrees = 0;
+ }
+
+ return NULL;
+}
+
/* Perform any pre-gimplification lowering of C++ front end trees to
GENERIC. */
@@ -978,7 +1047,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
if (__builtin_expect (wtd->omp_ctx != NULL, 0)
&& omp_var_to_track (TREE_OPERAND (stmt, 0)))
omp_cxx_notice_variable (wtd->omp_ctx, TREE_OPERAND (stmt, 0));
- *stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
+ *stmt_p = fold_convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0));
*walk_subtrees = 0;
}
else if (TREE_CODE (stmt) == RETURN_EXPR
@@ -1058,7 +1127,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
else if (TREE_CODE (stmt) == IF_STMT)
{
- genericize_if_stmt (stmt_p);
+ genericize_if_stmt (stmt_p, wtd->fold_hash);
/* *stmt_p has changed, tail recurse to handle it again. */
return cp_genericize_r (stmt_p, walk_subtrees, data);
}
@@ -1307,6 +1376,7 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
SIZEOF_EXPR, false);
if (*stmt_p == error_mark_node)
*stmt_p = size_one_node;
+ *stmt_p = cp_fold (*stmt_p, wtd->fold_hash);
return NULL;
}
else if ((flag_sanitize
@@ -1349,12 +1419,15 @@ cp_genericize_tree (tree* t_p)
{
struct cp_genericize_data wtd;
+ wtd.fold_hash = new hash_map<tree, tree>;
wtd.p_set = new hash_set<tree>;
wtd.bind_expr_stack.create (0);
wtd.omp_ctx = NULL;
wtd.try_block = NULL_TREE;
wtd.no_sanitize_p = false;
cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL);
+ cp_walk_tree (t_p, cp_fold_r, &wtd, NULL);
+ delete wtd.fold_hash;
delete wtd.p_set;
wtd.bind_expr_stack.release ();
if (flag_sanitize & SANITIZE_VPTR)
@@ -1782,3 +1855,483 @@ cxx_omp_disregard_value_expr (tree decl, bool shared)
&& DECL_LANG_SPECIFIC (decl)
&& DECL_OMP_PRIVATIZED_MEMBER (decl);
}
+
+/* Callback for walk_tree, looking for LABEL_EXPR. Return *TP if it is
+ a LABEL_EXPR; otherwise return NULL_TREE. Do not check the subtrees
+ of GOTO_EXPR. */
+
+static tree
+contains_label_1 (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
+{
+ switch (TREE_CODE (*tp))
+ {
+ case LABEL_EXPR:
+ return *tp;
+
+ case GOTO_EXPR:
+ *walk_subtrees = 0;
+
+ /* ... fall through ... */
+
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* Return whether the sub-tree ST contains a label which is accessible from
+ outside the sub-tree. */
+
+static bool
+contains_label_p (tree st)
+{
+ return
+ walk_tree_without_duplicates (&st, contains_label_1 , NULL) != NULL_TREE;
+}
+
+/* Perform folding on expression X. */
+
+tree
+cp_fully_fold (tree x)
+{
+ hash_map<tree, tree> *ctx = (scope_chain ? scope_chain->fold_map : NULL);
+ hash_map<tree, tree> *cv = (scope_chain ? scope_chain->cv_map : NULL);
+
+ /* If current scope has a hash_map, but it was for different CFUN,
+ then destroy hash_map to avoid issues with ggc_collect. */
+ if ((cv || ctx) && scope_chain->act_cfun != cfun)
+ {
+ if (ctx)
+ delete ctx;
+ if (cv)
+ delete cv;
+ ctx = NULL;
+ scope_chain->act_cfun = NULL;
+ scope_chain->fold_map = NULL;
+ scope_chain->cv_map = NULL;
+ }
+
+ /* If there is no hash_map, but there is a scope, and a set CFUN,
+ then create the hash_map for scope. */
+ if (!ctx && scope_chain && cfun)
+ {
+ ctx = scope_chain->fold_map = new hash_map <tree, tree>;
+ scope_chain->act_cfun = cfun;
+ }
+ /* Otherwise if there is no hash_map, use for folding temporary
+ hash_map. */
+ else if (!ctx)
+ {
+ hash_map<tree, tree> fold_hash;
+ return cp_fold (x, &fold_hash);
+ }
+
+ return cp_fold (x, ctx);
+}
+
+/* This function tries to fold given expression X in GENERIC-form.
+ For performance-reason, and for avoiding endless-recursion the
+ function uses given tree-hash FOLD_HASH.
+ If FOLD_HASH is 0, or we are processing within template-declaration,
+ or X is no valid expression, or has no valid type, we don't fold at all.
+ For performance-reason we don't hash on expressions representing a
+ declaration, or being of constant-class.
+ Function returns X, or its folded variant. */
+
+static tree
+cp_fold (tree x, hash_map<tree, tree> *fold_hash)
+{
+ tree *slot, op0, op1, op2, op3;
+ tree org_x = x, r = NULL_TREE;
+ enum tree_code code;
+ location_t loc;
+
+ if (!x || x == error_mark_node)
+ return x;
+
+ if (!fold_hash
+ || processing_template_decl
+ || (EXPR_P (x) && !TREE_TYPE (x)))
+ return x;
+
+ /* Don't even try to hash on DECLs or constants. */
+ if (DECL_P (x) || CONSTANT_CLASS_P (x))
+ return x;
+
+ slot = fold_hash->get (x);
+ if (slot && *slot)
+ return *slot;
+
+ code = TREE_CODE (x);
+ switch (code)
+ {
+ case SIZEOF_EXPR:
+ if (SIZEOF_EXPR_TYPE_P (x))
+ r = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (x, 0)),
+ SIZEOF_EXPR, false);
+ else if (TYPE_P (TREE_OPERAND (x, 0)))
+ r = cxx_sizeof_or_alignof_type (TREE_OPERAND (x, 0),
+ SIZEOF_EXPR, false);
+ else
+ r = cxx_sizeof_or_alignof_expr (TREE_OPERAND (x, 0),
+ SIZEOF_EXPR, false);
+ if (r == error_mark_node)
+ r = size_one_node;
+ x = r;
+ break;
+
+ case VIEW_CONVERT_EXPR:
+ case CONVERT_EXPR:
+ case NOP_EXPR:
+
+ if (VOID_TYPE_P (TREE_TYPE (x)))
+ return x;
+
+ if (!TREE_OPERAND (x, 0)
+ || TREE_CODE (TREE_OPERAND (x, 0)) == NON_LVALUE_EXPR)
+ return x;
+
+ loc = EXPR_LOCATION (x);
+ op0 = TREE_OPERAND (x, 0);
+
+ if (TREE_CODE (x) == NOP_EXPR
+ && TREE_OVERFLOW_P (op0)
+ && TREE_TYPE (x) == TREE_TYPE (op0))
+ return x;
+
+ op0 = cp_fold (op0, fold_hash);
+
+ if (op0 != TREE_OPERAND (x, 0))
+ x = build1_loc (loc, code, TREE_TYPE (x), op0);
+
+ x = fold (x);
+
+ /* Conversion of an out-of-range value has implementation-defined
+ behavior; the language considers it different from arithmetic
+ overflow, which is undefined. */
+ if (TREE_CODE (op0) == INTEGER_CST
+ && TREE_OVERFLOW_P (x) && !TREE_OVERFLOW_P (op0))
+ TREE_OVERFLOW (x) = false;
+
+ break;
+
+ case ALIGNOF_EXPR:
+ case SAVE_EXPR:
+ case ADDR_EXPR:
+ 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:
+ case UNARY_PLUS_EXPR:
+ case CLEANUP_POINT_EXPR:
+ case INDIRECT_REF:
+ /* case NON_LVALUE_EXPR: */
+ case RETURN_EXPR:
+ case EXPR_STMT:
+ case STMT_EXPR:
+ case GOTO_EXPR:
+ case EXIT_EXPR:
+ case LOOP_EXPR:
+
+ loc = EXPR_LOCATION (x);
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+ if (op0 != TREE_OPERAND (x, 0))
+ x = build1_loc (loc, code, TREE_TYPE (x), op0);
+
+ x = fold (x);
+
+ gcc_assert (TREE_CODE (x) != COND_EXPR
+ || !VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (x, 0))));
+ break;
+
+ case POSTDECREMENT_EXPR:
+ case POSTINCREMENT_EXPR:
+ case INIT_EXPR:
+
+ loc = EXPR_LOCATION (x);
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+ op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+
+ if (TREE_OPERAND (x, 0) != op0 || TREE_OPERAND (x, 1) != op1)
+ x = build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+
+ break;
+
+ case PREDECREMENT_EXPR:
+ case PREINCREMENT_EXPR:
+ case COMPOUND_EXPR:
+ 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_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ case TRUTH_AND_EXPR:
+ case TRUTH_ANDIF_EXPR:
+ case TRUTH_OR_EXPR:
+ case TRUTH_ORIF_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:
+ case MODIFY_EXPR:
+
+ loc = EXPR_LOCATION (x);
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+ op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+ if ((code == COMPOUND_EXPR || code == MODIFY_EXPR)
+ && ((op1 && TREE_SIDE_EFFECTS (op1))
+ || (op0 && TREE_SIDE_EFFECTS (op0))))
+ break;
+ if (TREE_CODE (x) == COMPOUND_EXPR && !op0)
+ op0 = build_empty_stmt (loc);
+
+ if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1))
+ x = build2_loc (loc, code, TREE_TYPE (x), op0, op1);
+
+ x = fold (x);
+
+ if (TREE_CODE (x) == COMPOUND_EXPR && TREE_OPERAND (x, 0) == NULL_TREE
+ && TREE_OPERAND (x, 1))
+ return TREE_OPERAND (x, 1);
+ break;
+
+ case VEC_COND_EXPR:
+ case COND_EXPR:
+
+ loc = EXPR_LOCATION (x);
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+ if (TREE_SIDE_EFFECTS (op0))
+ break;
+
+ op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+ op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+
+ if (TREE_CODE (op0) == INTEGER_CST)
+ {
+ tree un;
+
+ if (integer_zerop (op0))
+ {
+ un = op1;
+ r = op2;
+ }
+ else
+ {
+ un = op2;
+ r = op1;
+ }
+
+ if ((!TREE_SIDE_EFFECTS (un) || !contains_label_p (un))
+ && (! VOID_TYPE_P (TREE_TYPE (r)) || VOID_TYPE_P (x)))
+ {
+ if (CAN_HAVE_LOCATION_P (r)
+ && EXPR_LOCATION (r) != loc
+ && !(TREE_CODE (r) == SAVE_EXPR
+ || TREE_CODE (r) == TARGET_EXPR
+ || TREE_CODE (r) == BIND_EXPR))
+ {
+ r = copy_node (r);
+ SET_EXPR_LOCATION (r, loc);
+ }
+ x = r;
+ }
+
+ break;
+ }
+
+ if (VOID_TYPE_P (TREE_TYPE (x)))
+ break;
+
+ x = build3_loc (loc, code, TREE_TYPE (x), op0, op1, op2);
+
+ if (code != COND_EXPR)
+ x = fold (x);
+
+ break;
+
+ case CALL_EXPR:
+ {
+ int i, m, sv = optimize, nw = sv, changed = 0;
+ tree callee = get_callee_fndecl (x);
+
+ if (callee && DECL_BUILT_IN (callee) && !optimize
+ && DECL_IS_BUILTIN_CONSTANT_P (callee)
+ && current_function_decl
+ && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
+ nw = 1;
+ optimize = nw;
+ r = fold (x);
+ optimize = sv;
+
+ if (TREE_CODE (r) != CALL_EXPR)
+ {
+ x = cp_fold (r, fold_hash);
+ break;
+ }
+
+ x = copy_node (x);
+
+ m = call_expr_nargs (x);
+ for (i = 0; i < m; i++)
+ {
+ r = cp_fold (CALL_EXPR_ARG (x, i), fold_hash);
+ if (r != CALL_EXPR_ARG (x, i))
+ changed = 1;
+ CALL_EXPR_ARG (x, i) = r;
+ }
+
+ optimize = nw;
+ r = fold (x);
+ optimize = sv;
+
+ if (TREE_CODE (r) != CALL_EXPR)
+ {
+ x = cp_fold (r, fold_hash);
+ break;
+ }
+
+ optimize = nw;
+
+ /* Invoke maybe_constant_value for functions being declared
+ constexpr, and are no AGGR_INIT_EXPRs ...
+ TODO:
+ Due issues in maybe_constant_value for CALL_EXPR with
+ arguments passed by reference, it is disabled. */
+ if (callee && DECL_DECLARED_CONSTEXPR_P (callee))
+ r = maybe_constant_value (x);
+ optimize = sv;
+
+ if (TREE_CODE (r) != CALL_EXPR)
+ {
+ x = r;
+ break;
+ }
+
+ if (!changed)
+ x = org_x;
+ break;
+ }
+
+ case BIND_EXPR:
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+ op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+ op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+
+ if (TREE_OPERAND (x, 0) != op0 || TREE_OPERAND (x, 1) != op1 || TREE_OPERAND (x, 2) != op2)
+ {
+ x = copy_node (x);
+ TREE_OPERAND (x, 0) = op0;
+ TREE_OPERAND (x, 1) = op1;
+ TREE_OPERAND (x, 2) = op2;
+ }
+ break;
+
+ case CONSTRUCTOR:
+ {
+ unsigned i;
+ constructor_elt *p;
+ vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (x);
+ FOR_EACH_VEC_SAFE_ELT (elts, i, p)
+ p->value = cp_fold (p->value, fold_hash);
+ break;
+ }
+ case TREE_VEC:
+ {
+ bool changed = false;
+ vec<tree, va_gc> *vec = make_tree_vector ();
+ int i, n = TREE_VEC_LENGTH (x);
+ vec_safe_reserve (vec, n);
+
+ for (i = 0; i < n; i++)
+ {
+ tree op = cp_fold (TREE_VEC_ELT (x, i), fold_hash);
+ vec->quick_push (op);
+ if (op != TREE_VEC_ELT (x, i))
+ changed = true;
+ }
+
+ if (changed)
+ {
+ r = copy_node (x);
+ for (i = 0; i < n; i++)
+ TREE_VEC_ELT (r, i) = (*vec)[i];
+ x = r;
+ }
+
+ release_tree_vector (vec);
+ }
+
+ break;
+
+ case ARRAY_REF:
+ case ARRAY_RANGE_REF:
+
+ loc = EXPR_LOCATION (x);
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+ op1 = cp_fold (TREE_OPERAND (x, 1), fold_hash);
+ op2 = cp_fold (TREE_OPERAND (x, 2), fold_hash);
+ op3 = cp_fold (TREE_OPERAND (x, 3), fold_hash);
+
+ if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1)
+ || op2 != TREE_OPERAND (x, 2) || op3 != TREE_OPERAND (x, 3))
+ x = build4_loc (loc, code, TREE_TYPE (x), op0, op1, op2, op3);
+
+ x = fold (x);
+ break;
+
+ case DECL_EXPR:
+
+ op0 = cp_fold (TREE_OPERAND (x, 0), fold_hash);
+
+ if (op0 == TREE_OPERAND (x, 0))
+ break;
+
+ x = copy_node (x);
+ TREE_OPERAND (x, 0) = op0;
+ break;
+
+ default:
+ return org_x;
+ }
+
+ slot = &fold_hash->get_or_insert (org_x);
+ *slot = x;
+
+ /* Prevent that we try to fold an already folded result again. */
+ if (x != org_x)
+ {
+ slot = &fold_hash->get_or_insert (x);
+ *slot = x;
+ }
+
+ return x;
+}
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 828f268..5fc017a 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1239,6 +1239,11 @@ struct GTY(()) saved_scope {
hash_map<tree, tree> *GTY((skip)) x_local_specializations;
+ hash_map<tree, tree> *GTY((skip)) fold_map;
+ hash_map<tree, tree> *GTY((skip)) cv_map;
+
+ struct function *GTY((skip)) act_cfun;
+
struct saved_scope *prev;
};
@@ -6474,7 +6479,6 @@ extern tree cp_walk_subtrees (tree*, int*, walk_tree_fn,
walk_tree_1 (tp, func, data, pset, cp_walk_subtrees)
#define cp_walk_tree_without_duplicates(tp,func,data) \
walk_tree_without_duplicates_1 (tp, func, data, cp_walk_subtrees)
-extern tree fold_if_not_in_template (tree);
extern tree rvalue (tree);
extern tree convert_bitfield_to_declared_type (tree);
extern tree cp_save_expr (tree);
@@ -6705,6 +6709,7 @@ extern tree cxx_omp_clause_dtor (tree, tree);
extern void cxx_omp_finish_clause (tree, gimple_seq *);
extern bool cxx_omp_privatize_by_reference (const_tree);
extern bool cxx_omp_disregard_value_expr (tree, bool);
+extern tree cp_fully_fold (tree);
/* in name-lookup.c */
extern void suggest_alternatives_for (location_t, tree);
@@ -6796,6 +6801,7 @@ extern tree cxx_constant_value (tree, tree = NULL_TREE);
extern tree maybe_constant_value (tree, tree = NULL_TREE);
extern tree maybe_constant_init (tree, tree = NULL_TREE);
extern tree fold_non_dependent_expr (tree);
+extern tree fold_simple (tree);
extern bool is_sub_constant_expr (tree);
extern bool reduced_constant_expression_p (tree);
extern bool is_instantiation_of_constexpr (tree);
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index e764ee1..51b992c 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -53,7 +53,7 @@ static void diagnose_ref_binding (location_t, tree, tree, tree);
Here is a list of all the functions that assume that widening and
narrowing is always done with a NOP_EXPR:
- In convert.c, convert_to_integer.
+ In convert.c, convert_to_integer[_nofold].
In c-typeck.c, build_binary_op_nodefault (boolean ops),
and c_common_truthvalue_conversion.
In expr.c: expand_expr, for operands of a MULT_EXPR.
@@ -240,7 +240,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain)
gcc_assert (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr)))
== GET_MODE_SIZE (TYPE_MODE (type)));
- return convert_to_pointer (type, expr);
+ return convert_to_pointer_nofold (type, expr);
}
if (type_unknown_p (expr))
@@ -608,6 +608,7 @@ cp_fold_convert (tree type, tree expr)
conv = fold_convert (type, expr);
conv = ignore_overflows (conv, expr);
}
+
return conv;
}
@@ -633,7 +634,8 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
if (TREE_TYPE (expr) == type)
return expr;
-
+ if (expr == error_mark_node)
+ return expr;
result = cp_convert (type, expr, complain);
if ((complain & tf_warning)
@@ -641,13 +643,14 @@ cp_convert_and_check (tree type, tree expr, tsubst_flags_t complain)
{
tree folded = maybe_constant_value (expr);
tree stripped = folded;
- tree folded_result
+ tree folded_result;
+ folded_result
= folded != expr ? cp_convert (type, folded, complain) : result;
-
- /* maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW in a
- NOP_EXPR so that it isn't TREE_CONSTANT anymore. */
+ folded_result = cp_fully_fold (folded_result);
+ /* The maybe_constant_value wraps an INTEGER_CST with TREE_OVERFLOW
+ in a NOP_EXPR so that it isn't TREE_CONSTANT anymore. */
STRIP_NOPS (stripped);
-
+ folded = cp_fully_fold (folded);
if (!TREE_OVERFLOW_P (stripped)
&& folded_result != error_mark_node)
warnings_for_convert_and_check (input_location, type, folded,
@@ -706,9 +709,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
/* For complex data types, we need to perform componentwise
conversion. */
else if (TREE_CODE (type) == COMPLEX_TYPE)
- return fold_if_not_in_template (convert_to_complex (type, e));
+ return convert_to_complex_nofold (type, e);
else if (VECTOR_TYPE_P (type))
- return fold_if_not_in_template (convert_to_vector (type, e));
+ return convert_to_vector (type, e);
else if (TREE_CODE (e) == TARGET_EXPR)
{
/* Don't build a NOP_EXPR of class type. Instead, change the
@@ -721,7 +724,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
/* We shouldn't be treating objects of ADDRESSABLE type as
rvalues. */
gcc_assert (!TREE_ADDRESSABLE (type));
- return fold_if_not_in_template (build_nop (type, e));
+ return build_nop (type, e);
}
}
@@ -799,7 +802,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
return cp_truthvalue_conversion (e);
}
- converted = fold_if_not_in_template (convert_to_integer (type, e));
+ converted = convert_to_integer_nofold (type, e);
/* Ignore any integer overflow caused by the conversion. */
return ignore_overflows (converted, e);
@@ -811,7 +814,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
return nullptr_node;
}
if (POINTER_TYPE_P (type) || TYPE_PTRMEM_P (type))
- return fold_if_not_in_template (cp_convert_to_pointer (type, e, complain));
+ return cp_convert_to_pointer (type, e, complain);
if (code == VECTOR_TYPE)
{
tree in_vtype = TREE_TYPE (e);
@@ -826,7 +829,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
in_vtype, type);
return error_mark_node;
}
- return fold_if_not_in_template (convert_to_vector (type, e));
+ return convert_to_vector (type, e);
}
if (code == REAL_TYPE || code == COMPLEX_TYPE)
{
@@ -842,9 +845,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags,
TREE_TYPE (e));
}
if (code == REAL_TYPE)
- return fold_if_not_in_template (convert_to_real (type, e));
+ return convert_to_real_nofold (type, e);
else if (code == COMPLEX_TYPE)
- return fold_if_not_in_template (convert_to_complex (type, e));
+ return convert_to_complex_nofold (type, e);
}
/* New C++ semantics: since assignment is now based on
@@ -1457,7 +1460,7 @@ convert (tree type, tree expr)
intype = TREE_TYPE (expr);
if (POINTER_TYPE_P (type) && POINTER_TYPE_P (intype))
- return fold_if_not_in_template (build_nop (type, expr));
+ return build_nop (type, expr);
return ocp_convert (type, expr, CONV_OLD_CONVERT,
LOOKUP_NORMAL|LOOKUP_NO_CONVERSION,
@@ -1475,13 +1478,11 @@ convert_force (tree type, tree expr, int convtype, tsubst_flags_t complain)
enum tree_code code = TREE_CODE (type);
if (code == REFERENCE_TYPE)
- return (fold_if_not_in_template
- (convert_to_reference (type, e, CONV_C_CAST, 0,
- NULL_TREE, complain)));
+ return convert_to_reference (type, e, CONV_C_CAST, 0,
+ NULL_TREE, complain);
if (code == POINTER_TYPE)
- return fold_if_not_in_template (convert_to_pointer_force (type, e,
- complain));
+ return convert_to_pointer_force (type, e, complain);
/* From typeck.c convert_for_assignment */
if (((TYPE_PTR_P (TREE_TYPE (e)) && TREE_CODE (e) == ADDR_EXPR
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index bd3f2bc..484f4f2 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8580,35 +8580,6 @@ stabilize_vla_size (tree size)
cp_walk_tree (&size, stabilize_save_expr_r, &pset, &pset);
}
-/* Helper function for compute_array_index_type. Look for SIZEOF_EXPR
- not inside of SAVE_EXPR and fold them. */
-
-static tree
-fold_sizeof_expr_r (tree *expr_p, int *walk_subtrees, void *data)
-{
- tree expr = *expr_p;
- if (TREE_CODE (expr) == SAVE_EXPR || TYPE_P (expr))
- *walk_subtrees = 0;
- else if (TREE_CODE (expr) == SIZEOF_EXPR)
- {
- *(bool *)data = true;
- if (SIZEOF_EXPR_TYPE_P (expr))
- expr = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (expr, 0)),
- SIZEOF_EXPR, false);
- else if (TYPE_P (TREE_OPERAND (expr, 0)))
- expr = cxx_sizeof_or_alignof_type (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
- false);
- else
- expr = cxx_sizeof_or_alignof_expr (TREE_OPERAND (expr, 0), SIZEOF_EXPR,
- false);
- if (expr == error_mark_node)
- expr = size_one_node;
- *expr_p = expr;
- *walk_subtrees = 0;
- }
- return NULL;
-}
-
/* Given the SIZE (i.e., number of elements) in an array, compute an
appropriate index type for the array. If non-NULL, NAME is the
name of the thing being declared. */
@@ -8699,7 +8670,18 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
SET_TYPE_STRUCTURAL_EQUALITY (itype);
return itype;
}
-
+
+ if (TREE_CODE (size) != INTEGER_CST)
+ {
+ tree folded = cp_fully_fold (size);
+ if (TREE_CODE (folded) == INTEGER_CST)
+ pedwarn (location_of (size), OPT_Wpedantic,
+ "size of array is not an integral constant-expression");
+ /* Use the folded result for VLAs, too; it will have resolved
+ SIZEOF_EXPR. */
+ size = folded;
+ }
+
/* Normally, the array-bound will be a constant. */
if (TREE_CODE (size) == INTEGER_CST)
{
@@ -8786,7 +8768,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
cp_convert (ssizetype, integer_one_node,
complain),
complain);
- itype = fold (itype);
+ itype = maybe_constant_value (itype);
processing_template_decl = saved_processing_template_decl;
if (!TREE_CONSTANT (itype))
@@ -8794,18 +8776,6 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
/* A variable sized array. */
itype = variable_size (itype);
- if (TREE_CODE (itype) != SAVE_EXPR)
- {
- /* Look for SIZEOF_EXPRs in itype and fold them, otherwise
- they might survive till gimplification. */
- tree newitype = itype;
- bool found = false;
- cp_walk_tree_without_duplicates (&newitype,
- fold_sizeof_expr_r, &found);
- if (found)
- itype = variable_size (fold (newitype));
- }
-
stabilize_vla_size (itype);
if (flag_sanitize & SANITIZE_VLA
@@ -13515,7 +13485,7 @@ incremented enumerator value is too large for %<long%>");
"type %<%T%>", value, ENUM_UNDERLYING_TYPE (enumtype));
/* Convert the value to the appropriate type. */
- value = convert (ENUM_UNDERLYING_TYPE (enumtype), value);
+ value = fold_convert (ENUM_UNDERLYING_TYPE (enumtype), value);
}
}
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index a2d31a3..89859e9 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -3116,7 +3116,7 @@ get_guard_cond (tree guard, bool thread_safe)
{
guard_value = integer_one_node;
if (!same_type_p (TREE_TYPE (guard_value), TREE_TYPE (guard)))
- guard_value = convert (TREE_TYPE (guard), guard_value);
+ guard_value = fold_convert (TREE_TYPE (guard), guard_value);
guard = cp_build_binary_op (input_location,
BIT_AND_EXPR, guard, guard_value,
tf_warning_or_error);
@@ -3124,7 +3124,7 @@ get_guard_cond (tree guard, bool thread_safe)
guard_value = integer_zero_node;
if (!same_type_p (TREE_TYPE (guard_value), TREE_TYPE (guard)))
- guard_value = convert (TREE_TYPE (guard), guard_value);
+ guard_value = fold_convert (TREE_TYPE (guard), guard_value);
return cp_build_binary_op (input_location,
EQ_EXPR, guard, guard_value,
tf_warning_or_error);
@@ -3142,7 +3142,7 @@ set_guard (tree guard)
guard = get_guard_bits (guard);
guard_init = integer_one_node;
if (!same_type_p (TREE_TYPE (guard_init), TREE_TYPE (guard)))
- guard_init = convert (TREE_TYPE (guard), guard_init);
+ guard_init = fold_convert (TREE_TYPE (guard), guard_init);
return cp_build_modify_expr (guard, NOP_EXPR, guard_init,
tf_warning_or_error);
}
@@ -4573,6 +4573,19 @@ c_parse_final_cleanups (void)
/* If there are templates that we've put off instantiating, do
them now. */
instantiate_pending_templates (retries);
+ /* Clear fold_map and/or cv_map of current scope, if present. */
+ if (scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+ {
+ hash_map<tree,tree> *fm = scope_chain->fold_map;
+ hash_map<tree,tree> *cv = scope_chain->cv_map;
+ scope_chain->fold_map = NULL;
+ scope_chain->cv_map = NULL;
+ scope_chain->act_cfun = NULL;
+ if (fm)
+ delete fm;
+ if (cv)
+ delete cv;
+ }
ggc_collect ();
/* Write out virtual tables as required. Note that writing out
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index b45281f..fd9ae0d 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -178,9 +178,9 @@ build_zero_init_1 (tree type, tree nelts, bool static_storage_p,
initialized are initialized to zero. */
;
else if (TYPE_PTR_OR_PTRMEM_P (type))
- init = convert (type, nullptr_node);
+ init = fold (convert (type, nullptr_node));
else if (SCALAR_TYPE_P (type))
- init = convert (type, integer_zero_node);
+ init = fold (convert (type, integer_zero_node));
else if (RECORD_OR_UNION_CODE_P (TREE_CODE (type)))
{
tree field;
@@ -794,7 +794,6 @@ perform_member_init (tree member, tree init)
in that case. */
init = build_x_compound_expr_from_list (init, ELK_MEM_INIT,
tf_warning_or_error);
-
if (init)
finish_expr_stmt (cp_build_modify_expr (decl, INIT_EXPR, init,
tf_warning_or_error));
@@ -2712,7 +2711,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
}
max_outer_nelts_tree = wide_int_to_tree (sizetype, max_outer_nelts);
- size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
+ size = size_binop (MULT_EXPR, size, fold_convert (sizetype, nelts));
outer_nelts_check = fold_build2 (LE_EXPR, boolean_type_node,
outer_nelts,
max_outer_nelts_tree);
@@ -2872,7 +2871,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts,
{
placement_expr = get_target_expr (placement_first);
CALL_EXPR_ARG (alloc_call, 1)
- = convert (TREE_TYPE (placement), placement_expr);
+ = fold_convert (TREE_TYPE (placement), placement_expr);
}
if (!member_new_p
@@ -3464,7 +3463,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
/* The below is short by the cookie size. */
virtual_size = size_binop (MULT_EXPR, size_exp,
- convert (sizetype, maxindex));
+ fold_convert (sizetype, maxindex));
tbase = create_temporary_var (ptype);
tbase_init
@@ -3507,7 +3506,7 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
/* The below is short by the cookie size. */
virtual_size = size_binop (MULT_EXPR, size_exp,
- convert (sizetype, maxindex));
+ fold_convert (sizetype, maxindex));
if (! TYPE_VEC_NEW_USES_COOKIE (type))
/* no header */
@@ -3553,8 +3552,8 @@ build_vec_delete_1 (tree base, tree maxindex, tree type,
body = fold_build3_loc (input_location, COND_EXPR, void_type_node,
fold_build2_loc (input_location,
NE_EXPR, boolean_type_node, base,
- convert (TREE_TYPE (base),
- nullptr_node)),
+ fold_convert (TREE_TYPE (base),
+ nullptr_node)),
body, integer_zero_node);
body = build1 (NOP_EXPR, void_type_node, body);
@@ -3676,6 +3675,7 @@ build_vec_init (tree base, tree maxindex, tree init,
if (maxindex == NULL_TREE || maxindex == error_mark_node)
return error_mark_node;
+ maxindex = maybe_constant_value (maxindex);
if (explicit_value_init_p)
gcc_assert (!init);
@@ -3717,6 +3717,8 @@ build_vec_init (tree base, tree maxindex, tree init,
}
maxindex = cp_convert (ptrdiff_type_node, maxindex, complain);
+ maxindex = fold_simple (maxindex);
+
if (TREE_CODE (atype) == ARRAY_TYPE)
{
ptype = build_pointer_type (type);
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index 8744fff..61a352a 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -6182,6 +6182,19 @@ push_to_top_level (void)
s->unevaluated_operand = cp_unevaluated_operand;
s->inhibit_evaluation_warnings = c_inhibit_evaluation_warnings;
s->x_stmt_tree.stmts_are_full_exprs_p = true;
+ if (current_function_decl
+ && scope_chain && scope_chain->function_decl == current_function_decl
+ && cfun && scope_chain->act_cfun == cfun)
+ {
+ s->fold_map = scope_chain->fold_map;
+ s->cv_map = scope_chain->cv_map;
+ }
+ else
+ {
+ s->fold_map = NULL;
+ s->cv_map = NULL;
+ }
+ s->act_cfun = cfun;
scope_chain = s;
current_function_decl = NULL_TREE;
@@ -6199,7 +6212,10 @@ pop_from_top_level_1 (void)
{
struct saved_scope *s = scope_chain;
cxx_saved_binding *saved;
+ hash_map<tree, tree> *fm = s->fold_map;
+ hash_map<tree, tree> *cv = s->cv_map;
size_t i;
+ bool same_fold_map = false;
/* Clear out class-level bindings cache. */
if (previous_class_level)
@@ -6221,9 +6237,32 @@ pop_from_top_level_1 (void)
state. */
if (s->need_pop_function_context)
pop_function_context ();
+
+ /* If 'current_function_decl' isn't NULL and is equal to prior pushed,
+ we are within a nested function.
+ If additionally saved 'cfun' is identical to current, we can use
+ the same 'fold_map'. */
+
+ if (current_function_decl && s->function_decl == current_function_decl
+ && scope_chain && s->fold_map == scope_chain->fold_map
+ && scope_chain->act_cfun && scope_chain->act_cfun == cfun)
+ same_fold_map = true;
+
current_function_decl = s->function_decl;
cp_unevaluated_operand = s->unevaluated_operand;
c_inhibit_evaluation_warnings = s->inhibit_evaluation_warnings;
+
+ /* If we have a new 'fold_map', and it isn't equal, or outside of
+ scope_chain, then invalidate it. */
+ if (fm && (!same_fold_map || !scope_chain))
+ delete fm;
+ if (cv && (!same_fold_map || !scope_chain))
+ delete cv;
+
+ /* Invalidate explicit. */
+ s->fold_map = NULL;
+ s->cv_map = NULL;
+ s->act_cfun = NULL;
}
/* Wrapper for pop_from_top_level_1. */
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d1f4970..24a77f8 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -6769,7 +6769,7 @@ cp_parser_array_notation (location_t loc, cp_parser *parser, tree *init_index,
2. ARRAY [ EXP : EXP ]
3. ARRAY [ EXP : EXP : EXP ] */
- *init_index = cp_parser_expression (parser);
+ *init_index = cp_parser_expression (parser);
if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON)
{
/* This indicates that we have a normal array expression. */
@@ -8513,9 +8513,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
/* For "false && x" or "true || x", x will never be executed;
disable warnings while evaluating it. */
if (current.tree_type == TRUTH_ANDIF_EXPR)
- c_inhibit_evaluation_warnings += current.lhs == truthvalue_false_node;
+ c_inhibit_evaluation_warnings +=
+ cp_fully_fold (current.lhs) == truthvalue_false_node;
else if (current.tree_type == TRUTH_ORIF_EXPR)
- c_inhibit_evaluation_warnings += current.lhs == truthvalue_true_node;
+ c_inhibit_evaluation_warnings +=
+ cp_fully_fold (current.lhs) == truthvalue_true_node;
/* Extract another operand. It may be the RHS of this expression
or the LHS of a new, higher priority expression. */
@@ -8562,9 +8564,11 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
/* Undo the disabling of warnings done above. */
if (current.tree_type == TRUTH_ANDIF_EXPR)
- c_inhibit_evaluation_warnings -= current.lhs == truthvalue_false_node;
+ c_inhibit_evaluation_warnings -=
+ cp_fully_fold (current.lhs) == truthvalue_false_node;
else if (current.tree_type == TRUTH_ORIF_EXPR)
- c_inhibit_evaluation_warnings -= current.lhs == truthvalue_true_node;
+ c_inhibit_evaluation_warnings -=
+ cp_fully_fold (current.lhs) == truthvalue_true_node;
if (warn_logical_not_paren
&& TREE_CODE_CLASS (current.tree_type) == tcc_comparison
@@ -8650,7 +8654,7 @@ cp_parser_binary_expression (cp_parser* parser, bool cast_p,
static tree
cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
{
- tree expr;
+ tree expr, folded_logical_or_expr = cp_fully_fold (logical_or_expr);
tree assignment_expr;
struct cp_token *token;
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -8665,7 +8669,8 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
"ISO C++ does not allow ?: with omitted middle operand");
/* Implicit true clause. */
expr = NULL_TREE;
- c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_true_node;
+ c_inhibit_evaluation_warnings +=
+ folded_logical_or_expr == truthvalue_true_node;
warn_for_omitted_condop (token->location, logical_or_expr);
}
else
@@ -8673,11 +8678,12 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
bool saved_colon_corrects_to_scope_p = parser->colon_corrects_to_scope_p;
parser->colon_corrects_to_scope_p = false;
/* Parse the expression. */
- c_inhibit_evaluation_warnings += logical_or_expr == truthvalue_false_node;
+ c_inhibit_evaluation_warnings +=
+ folded_logical_or_expr == truthvalue_false_node;
expr = cp_parser_expression (parser);
c_inhibit_evaluation_warnings +=
- ((logical_or_expr == truthvalue_true_node)
- - (logical_or_expr == truthvalue_false_node));
+ ((folded_logical_or_expr == truthvalue_true_node)
+ - (folded_logical_or_expr == truthvalue_false_node));
parser->colon_corrects_to_scope_p = saved_colon_corrects_to_scope_p;
}
@@ -8685,7 +8691,8 @@ cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
cp_parser_require (parser, CPP_COLON, RT_COLON);
/* Parse the assignment-expression. */
assignment_expr = cp_parser_assignment_expression (parser);
- c_inhibit_evaluation_warnings -= logical_or_expr == truthvalue_true_node;
+ c_inhibit_evaluation_warnings -=
+ folded_logical_or_expr == truthvalue_true_node;
/* Build the conditional-expression. */
return build_x_conditional_expr (loc, logical_or_expr,
@@ -20330,8 +20337,8 @@ cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
{
initializer
= cp_parser_constant_expression (parser,
- /*allow_non_constant_p=*/true,
- non_constant_p);
+ /*allow_non_constant_p=*/true,
+ non_constant_p);
}
else
initializer = cp_parser_braced_list (parser, non_constant_p);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index bfea8e2..fb9cdf8 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -6217,7 +6217,7 @@ convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
/* 14.3.2/5: The null pointer{,-to-member} conversion is applied
to a non-type argument of "nullptr". */
if (expr == nullptr_node && TYPE_PTR_OR_PTRMEM_P (type))
- expr = convert (type, expr);
+ expr = fold_simple (convert (type, expr));
/* In C++11, integral or enumeration non-type template arguments can be
arbitrary constant expressions. Pointer and pointer to
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 7702a41..73f05f0 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -2569,9 +2569,26 @@ 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);
+ tree result_ovl, expr_ovl;
+
+ if (!(complain & tf_warning))
+ return result;
+
+ result_ovl = result;
+ expr_ovl = expr;
+
+ if (!processing_template_decl)
+ expr_ovl = cp_fully_fold (expr_ovl);
+
+ if (!CONSTANT_CLASS_P (expr_ovl)
+ || TREE_OVERFLOW_P (expr_ovl))
+ return result;
+
+ if (!processing_template_decl)
+ result_ovl = cp_fully_fold (result_ovl);
+
+ if (CONSTANT_CLASS_P (result_ovl) && TREE_OVERFLOW_P (result_ovl))
+ overflow_warning (input_location, result_ovl);
return result;
}
@@ -3895,6 +3912,7 @@ finish_offsetof (tree expr, location_t loc)
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)
@@ -4049,6 +4067,22 @@ emit_associated_thunks (tree fn)
bool
expand_or_defer_fn_1 (tree fn)
{
+ if (!function_depth)
+ {
+ if (scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+ {
+ hash_map<tree, tree> *fm = scope_chain->fold_map;
+ hash_map<tree, tree> *cv = scope_chain->cv_map;
+ if (fm)
+ delete fm;
+ if (cv)
+ delete cv;
+ scope_chain->fold_map = NULL;
+ scope_chain->cv_map = NULL;
+ scope_chain->act_cfun = NULL;
+ }
+ }
+
/* 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)
@@ -4129,6 +4163,19 @@ expand_or_defer_fn (tree fn)
emit_associated_thunks (fn);
function_depth--;
+ if (function_depth == 0
+ && scope_chain && (scope_chain->fold_map || scope_chain->cv_map))
+ {
+ hash_map<tree, tree> *fm = scope_chain->fold_map;
+ hash_map<tree, tree> *cv = scope_chain->cv_map;
+ scope_chain->fold_map = NULL;
+ scope_chain->cv_map = NULL;
+ scope_chain->act_cfun = NULL;
+ if (fm)
+ delete fm;
+ if (cv)
+ delete cv;
+ }
}
}
@@ -4483,6 +4530,11 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types,
low_bound = mark_rvalue_use (low_bound);
if (length)
length = mark_rvalue_use (length);
+ /* We need to reduce to real constant-values for checks below. */
+ if (length)
+ length = fold_simple (length);
+ if (low_bound)
+ low_bound = fold_simple (low_bound);
if (low_bound
&& TREE_CODE (low_bound) == INTEGER_CST
&& TYPE_PRECISION (TREE_TYPE (low_bound))
@@ -6178,7 +6230,8 @@ finish_omp_clauses (tree clauses, bool allow_fields, bool declare_simd)
if (OMP_CLAUSE_SCHEDULE_KIND (c)
== OMP_CLAUSE_SCHEDULE_CILKFOR)
{
- t = convert_to_integer (long_integer_type_node, t);
+ t = convert_to_integer_nofold (long_integer_type_node,
+ t);
if (t == error_mark_node)
{
remove = true;
@@ -7447,6 +7500,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
if (init && EXPR_HAS_LOCATION (init))
elocus = EXPR_LOCATION (init);
+ cond = cp_fully_fold (cond);
switch (TREE_CODE (cond))
{
case GT_EXPR:
@@ -7482,6 +7536,7 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
diff = build_x_binary_op (elocus, MINUS_EXPR, TREE_OPERAND (cond, 1),
ERROR_MARK, iter, ERROR_MARK, NULL,
tf_warning_or_error);
+ diff = cp_fully_fold (diff);
if (error_operand_p (diff))
return true;
if (TREE_CODE (TREE_TYPE (diff)) != INTEGER_TYPE)
@@ -7543,8 +7598,9 @@ handle_omp_for_class_iterator (int i, location_t locus, enum tree_code code,
if (TREE_CODE (rhs) == MINUS_EXPR)
{
incr = build1 (NEGATE_EXPR, TREE_TYPE (diff), incr);
- incr = fold_if_not_in_template (incr);
+ incr = fold_simple (incr);
}
+
if (TREE_CODE (incr) != INTEGER_CST
&& (TREE_CODE (incr) != NOP_EXPR
|| (TREE_CODE (TREE_OPERAND (incr, 0))
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 4311212..dd4daed 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -308,9 +308,19 @@ xvalue_p (const_tree ref)
bool
builtin_valid_in_constant_expr_p (const_tree decl)
{
- /* At present BUILT_IN_CONSTANT_P is the only builtin we're allowing
- in constant-expressions. We may want to add other builtins later. */
- return DECL_IS_BUILTIN_CONSTANT_P (decl);
+ if (!(TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl)))
+ /* Not a built-in. */
+ return false;
+ switch (DECL_FUNCTION_CODE (decl))
+ {
+ case BUILT_IN_CONSTANT_P:
+ case BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE:
+ /* These have constant results even if their operands are
+ non-constant. */
+ return true;
+ default:
+ return false;
+ }
}
/* Build a TARGET_EXPR, initializing the DECL with the VALUE. */
@@ -686,8 +696,8 @@ convert_bitfield_to_declared_type (tree expr)
bitfield_type = is_bitfield_expr_with_lowered_type (expr);
if (bitfield_type)
- expr = convert_to_integer (TYPE_MAIN_VARIANT (bitfield_type),
- expr);
+ expr = convert_to_integer_nofold (TYPE_MAIN_VARIANT (bitfield_type),
+ expr);
return expr;
}
@@ -3484,10 +3494,13 @@ handle_init_priority_attribute (tree* node,
STRIP_NOPS (initp_expr);
initp_expr = default_conversion (initp_expr);
+ if (initp_expr)
+ initp_expr = maybe_constant_value (initp_expr);
if (!initp_expr || TREE_CODE (initp_expr) != INTEGER_CST)
{
error ("requested init_priority is not an integer constant");
+ cxx_constant_value (initp_expr);
*no_add_attrs = true;
return NULL_TREE;
}
@@ -4262,26 +4275,6 @@ stabilize_init (tree init, tree *initp)
return !TREE_SIDE_EFFECTS (init);
}
-/* Like "fold", but should be used whenever we might be processing the
- body of a template. */
-
-tree
-fold_if_not_in_template (tree expr)
-{
- /* In the body of a template, there is never any need to call
- "fold". We will call fold later when actually instantiating the
- template. Integral constant expressions in templates will be
- evaluated via instantiate_non_dependent_expr, as necessary. */
- if (processing_template_decl)
- return expr;
-
- /* Fold C++ front-end specific tree codes. */
- if (TREE_CODE (expr) == UNARY_PLUS_EXPR)
- return fold_convert (TREE_TYPE (expr), TREE_OPERAND (expr, 0));
-
- return fold (expr);
-}
-
/* Returns true if a cast to TYPE may appear in an integral constant
expression. */
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 0501e4d..4e7ef58 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1948,8 +1948,6 @@ decay_conversion (tree exp,
code = TREE_CODE (type);
- /* FIXME remove for delayed folding. */
- exp = scalar_constant_value (exp);
if (error_operand_p (exp))
return error_mark_node;
@@ -2442,7 +2440,6 @@ build_class_member_access_expr (tree object, tree member,
result = build3_loc (input_location, COMPONENT_REF, member_type,
object, member, NULL_TREE);
- result = fold_if_not_in_template (result);
/* Mark the expression const or volatile, as appropriate. Even
though we've dealt with the type above, we still have to mark the
@@ -2855,9 +2852,9 @@ build_simple_component_ref (tree object, tree member)
{
tree type = cp_build_qualified_type (TREE_TYPE (member),
cp_type_quals (TREE_TYPE (object)));
- return fold_build3_loc (input_location,
- COMPONENT_REF, type,
- object, member, NULL_TREE);
+ return build3_loc (input_location,
+ COMPONENT_REF, type,
+ object, member, NULL_TREE);
}
/* Return an expression for the MEMBER_NAME field in the internal
@@ -3176,8 +3173,7 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
|= (CP_TYPE_VOLATILE_P (type) | TREE_SIDE_EFFECTS (array));
TREE_THIS_VOLATILE (rval)
|= (CP_TYPE_VOLATILE_P (type) | TREE_THIS_VOLATILE (array));
- ret = require_complete_type_sfinae (fold_if_not_in_template (rval),
- complain);
+ ret = require_complete_type_sfinae (rval, complain);
protected_set_expr_location (ret, loc);
if (non_lvalue)
ret = non_lvalue_loc (loc, ret);
@@ -3924,7 +3920,6 @@ build_vec_cmp (tree_code code, tree type,
tree minus_one_vec = build_minus_one_cst (type);
tree cmp_type = build_same_sized_truth_vector_type(type);
tree cmp = build2 (code, cmp_type, arg0, arg1);
- cmp = fold_if_not_in_template (cmp);
return build3 (VEC_COND_EXPR, type, cmp, minus_one_vec, zero_vec);
}
@@ -3979,7 +3974,7 @@ cp_build_binary_op (location_t location,
convert it to this type. */
tree final_type = 0;
- tree result;
+ tree result, result_ovl;
tree orig_type = NULL;
/* Nonzero if this is an operation like MIN or MAX which can
@@ -4602,7 +4597,7 @@ cp_build_binary_op (location_t location,
op0 = cp_build_binary_op (location,
TRUTH_ANDIF_EXPR, e1, e2,
complain);
- op1 = cp_convert (TREE_TYPE (op0), integer_one_node, complain);
+ op1 = cp_convert (TREE_TYPE (op0), integer_one_node, complain);
}
else
{
@@ -4643,10 +4638,12 @@ cp_build_binary_op (location_t location,
op1 = save_expr (op1);
pfn0 = pfn_from_ptrmemfunc (op0);
+ pfn0 = cp_fully_fold (pfn0);
/* Avoid -Waddress warnings (c++/64877). */
if (TREE_CODE (pfn0) == ADDR_EXPR)
TREE_NO_WARNING (pfn0) = 1;
pfn1 = pfn_from_ptrmemfunc (op1);
+ pfn1 = cp_fully_fold (pfn1);
delta0 = delta_from_ptrmemfunc (op0);
delta1 = delta_from_ptrmemfunc (op1);
if (TARGET_PTRMEMFUNC_VBIT_LOCATION
@@ -5000,10 +4997,7 @@ cp_build_binary_op (location_t location,
gcc_unreachable();
}
}
- real = fold_if_not_in_template (real);
- imag = fold_if_not_in_template (imag);
result = build2 (COMPLEX_EXPR, result_type, real, imag);
- result = fold_if_not_in_template (result);
return result;
}
@@ -5031,20 +5025,12 @@ cp_build_binary_op (location_t location,
if (short_compare)
{
- /* Don't write &op0, etc., because that would prevent op0
- from being kept in a register.
- Instead, make copies of the our local variables and
- pass the copies by reference, then copy them back afterward. */
- tree xop0 = op0, xop1 = op1, xresult_type = result_type;
+ /* We call shorten_compare only for diagnostic-reason. */
+ tree xop0 = fold_simple (op0), xop1 = fold_simple (op1),
+ xresult_type = result_type;
enum tree_code xresultcode = resultcode;
- tree val
- = shorten_compare (location, &xop0, &xop1, &xresult_type,
+ shorten_compare (location, &xop0, &xop1, &xresult_type,
&xresultcode);
- if (val != 0)
- return cp_convert (boolean_type_node, val, complain);
- op0 = xop0, op1 = xop1;
- converted = 1;
- resultcode = xresultcode;
}
if ((short_compare || code == MIN_EXPR || code == MAX_EXPR)
@@ -5063,9 +5049,9 @@ cp_build_binary_op (location_t location,
tree oop1 = maybe_constant_value (orig_op1);
if (TREE_CODE (oop0) != INTEGER_CST)
- oop0 = orig_op0;
+ oop0 = cp_fully_fold (orig_op0);
if (TREE_CODE (oop1) != INTEGER_CST)
- oop1 = orig_op1;
+ oop1 = cp_fully_fold (orig_op1);
warn_for_sign_compare (location, oop0, oop1, op0, op1,
result_type, resultcode);
}
@@ -5120,18 +5106,30 @@ cp_build_binary_op (location_t location,
}
result = build2 (resultcode, build_type, op0, op1);
- result = fold_if_not_in_template (result);
if (final_type != 0)
result = cp_convert (final_type, result, complain);
- if (TREE_OVERFLOW_P (result)
- && !TREE_OVERFLOW_P (op0)
- && !TREE_OVERFLOW_P (op1))
- overflow_warning (location, result);
-
if (instrument_expr != NULL)
- result = fold_build2 (COMPOUND_EXPR, TREE_TYPE (result),
- instrument_expr, result);
+ result = build2 (COMPOUND_EXPR, TREE_TYPE (result),
+ instrument_expr, result);
+
+ if (!processing_template_decl)
+ {
+ op0 = cp_fully_fold (op0);
+ /* Only consider the second argument if the first isn't overflowed. */
+ if (!CONSTANT_CLASS_P (op0) || TREE_OVERFLOW_P (op0))
+ return result;
+ op1 = cp_fully_fold (op1);
+ if (!CONSTANT_CLASS_P (op1) || TREE_OVERFLOW_P (op1))
+ return result;
+ }
+ else if (!CONSTANT_CLASS_P (op0) || !CONSTANT_CLASS_P (op1)
+ || TREE_OVERFLOW_P (op0) || TREE_OVERFLOW_P (op1))
+ return result;
+
+ result_ovl = fold_build2 (resultcode, build_type, op0, op1);
+ if (TREE_OVERFLOW_P (result_ovl))
+ overflow_warning (location, result_ovl);
return result;
}
@@ -5181,8 +5179,7 @@ cp_pointer_int_sum (enum tree_code resultcode, tree ptrop, tree intop,
complete_type (TREE_TYPE (res_type));
return pointer_int_sum (input_location, resultcode, ptrop,
- fold_if_not_in_template (intop),
- complain & tf_warning_or_error);
+ intop, complain & tf_warning_or_error);
}
/* Return a tree for the difference of pointers OP0 and OP1.
@@ -5258,7 +5255,7 @@ pointer_diff (tree op0, tree op1, tree ptrtype, tsubst_flags_t complain)
result = build2 (EXACT_DIV_EXPR, restype, op0,
cp_convert (restype, op1, complain));
- return fold_if_not_in_template (result);
+ return result;
}
/* Construct and perhaps optimize a tree representation
@@ -5774,6 +5771,10 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
/* Make sure the result is not an lvalue: a unary plus or minus
expression is always a rvalue. */
arg = rvalue (arg);
+
+ if (code == NEGATE_EXPR && CONSTANT_CLASS_P (arg))
+ /* Immediately fold negation of a constant. */
+ return fold_build1 (code, TREE_TYPE (arg), arg);
}
}
break;
@@ -5838,10 +5839,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
case REALPART_EXPR:
case IMAGPART_EXPR:
arg = build_real_imag_expr (input_location, code, arg);
- if (arg == error_mark_node)
- return arg;
- else
- return fold_if_not_in_template (arg);
+ return arg;
case PREINCREMENT_EXPR:
case POSTINCREMENT_EXPR:
@@ -6008,7 +6006,7 @@ cp_build_unary_op (enum tree_code code, tree xarg, int noconvert,
{
if (argtype == 0)
argtype = TREE_TYPE (arg);
- return fold_if_not_in_template (build1 (code, argtype, arg));
+ return build1 (code, argtype, arg);
}
if (complain & tf_error)
@@ -7002,7 +7000,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
return rvalue (expr);
else if ((TYPE_PTRFN_P (type) && TYPE_PTRFN_P (intype))
|| (TYPE_PTRMEMFUNC_P (type) && TYPE_PTRMEMFUNC_P (intype)))
- return fold_if_not_in_template (build_nop (type, expr));
+ return build_nop (type, expr);
else if ((TYPE_PTRDATAMEM_P (type) && TYPE_PTRDATAMEM_P (intype))
|| (TYPE_PTROBV_P (type) && TYPE_PTROBV_P (intype)))
{
@@ -7030,7 +7028,7 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
if (warn_strict_aliasing <= 2)
strict_aliasing_warning (intype, type, sexpr);
- return fold_if_not_in_template (build_nop (type, expr));
+ return build_nop (type, expr);
}
else if ((TYPE_PTRFN_P (type) && TYPE_PTROBV_P (intype))
|| (TYPE_PTRFN_P (intype) && TYPE_PTROBV_P (type)))
@@ -7041,13 +7039,13 @@ build_reinterpret_cast_1 (tree type, tree expr, bool c_cast_p,
warning (OPT_Wconditionally_supported,
"casting between pointer-to-function and pointer-to-object "
"is conditionally-supported");
- return fold_if_not_in_template (build_nop (type, expr));
+ return build_nop (type, expr);
}
else if (VECTOR_TYPE_P (type))
- return fold_if_not_in_template (convert_to_vector (type, expr));
+ return convert_to_vector (type, expr);
else if (VECTOR_TYPE_P (intype)
&& INTEGRAL_OR_ENUMERATION_TYPE_P (type))
- return fold_if_not_in_template (convert_to_integer (type, expr));
+ return convert_to_integer_nofold (type, expr);
else
{
if (valid_p)
@@ -7899,8 +7897,7 @@ get_delta_difference (tree from, tree to,
}
}
- return fold_if_not_in_template (convert_to_integer (ptrdiff_type_node,
- result));
+ return convert_to_integer (ptrdiff_type_node, result);
}
/* Return a constructor for the pointer-to-member-function TYPE using
@@ -8081,41 +8078,35 @@ expand_ptrmemfunc_cst (tree cst, tree *delta, tree *pfn)
fn; the call will do the opposite adjustment. */
tree orig_class = DECL_CONTEXT (fn);
tree binfo = binfo_or_else (orig_class, fn_class);
- *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
- *delta, BINFO_OFFSET (binfo));
- *delta = fold_if_not_in_template (*delta);
+ *delta = fold_build2 (PLUS_EXPR, TREE_TYPE (*delta),
+ *delta, BINFO_OFFSET (binfo));
/* We set PFN to the vtable offset at which the function can be
found, plus one (unless ptrmemfunc_vbit_in_delta, in which
case delta is shifted left, and then incremented). */
*pfn = DECL_VINDEX (fn);
- *pfn = build2 (MULT_EXPR, integer_type_node, *pfn,
- TYPE_SIZE_UNIT (vtable_entry_type));
- *pfn = fold_if_not_in_template (*pfn);
+ *pfn = fold_build2 (MULT_EXPR, integer_type_node, *pfn,
+ TYPE_SIZE_UNIT (vtable_entry_type));
switch (TARGET_PTRMEMFUNC_VBIT_LOCATION)
{
case ptrmemfunc_vbit_in_pfn:
- *pfn = build2 (PLUS_EXPR, integer_type_node, *pfn,
- integer_one_node);
- *pfn = fold_if_not_in_template (*pfn);
+ *pfn = fold_build2 (PLUS_EXPR, integer_type_node, *pfn,
+ integer_one_node);
break;
case ptrmemfunc_vbit_in_delta:
- *delta = build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
- *delta, integer_one_node);
- *delta = fold_if_not_in_template (*delta);
- *delta = build2 (PLUS_EXPR, TREE_TYPE (*delta),
- *delta, integer_one_node);
- *delta = fold_if_not_in_template (*delta);
+ *delta = fold_build2 (LSHIFT_EXPR, TREE_TYPE (*delta),
+ *delta, integer_one_node);
+ *delta = fold_build2 (PLUS_EXPR, TREE_TYPE (*delta),
+ *delta, integer_one_node);
break;
default:
gcc_unreachable ();
}
- *pfn = build_nop (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
- *pfn = fold_if_not_in_template (*pfn);
+ *pfn = fold_convert (TYPE_PTRMEMFUNC_FN_TYPE (type), *pfn);
}
}
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index e73ea13..7544333 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -742,6 +742,7 @@ split_nonconstant_init (tree dest, tree init)
init = TARGET_EXPR_INITIAL (init);
if (TREE_CODE (init) == CONSTRUCTOR)
{
+ init = cp_fully_fold (init);
code = push_stmt_list ();
if (split_nonconstant_init_1 (dest, init))
init = NULL_TREE;
@@ -832,6 +833,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init;
TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl);
}
+ value = cp_fully_fold (value);
if (cxx_dialect >= cxx14 && CLASS_TYPE_P (strip_array_types (type)))
/* Handle aggregate NSDMI in non-constant initializers, too. */
@@ -930,19 +932,35 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
}
}
+ bool almost_ok = ok;
+ if (!ok && !CONSTANT_CLASS_P (init) && (complain & tf_warning_or_error))
+ {
+ tree folded = cp_fully_fold (init);
+ if (TREE_CONSTANT (folded) && check_narrowing (type, folded, tf_none))
+ almost_ok = true;
+ }
+
if (!ok)
{
+ location_t loc = EXPR_LOC_OR_LOC (init, input_location);
if (cxx_dialect == cxx98)
- warning_at (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
- "narrowing conversion of %qE from %qT to %qT inside { } "
- "is ill-formed in C++11", init, ftype, type);
- else if (!TREE_CONSTANT (init))
+ {
+ if (complain & tf_warning)
+ warning_at (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
+ "from %qT to %qT inside { } is ill-formed in C++11",
+ init, ftype, type);
+ ok = true;
+ }
+ else if (!CONSTANT_CLASS_P (init))
{
if (complain & tf_warning_or_error)
{
- pedwarn (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
- "narrowing conversion of %qE from %qT to %qT inside { }",
- init, ftype, type);
+ if (!almost_ok || pedantic)
+ pedwarn (loc, OPT_Wnarrowing, "narrowing conversion of %qE "
+ "from %qT to %qT inside { }", init, ftype, type);
+ if (pedantic && almost_ok)
+ inform (loc, " the expression has a constant value but is not "
+ "a C++ constant-expression");
ok = true;
}
}
@@ -950,7 +968,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
{
int savederrorcount = errorcount;
global_dc->pedantic_errors = 1;
- pedwarn (EXPR_LOC_OR_LOC (init, input_location), OPT_Wnarrowing,
+ pedwarn (loc, OPT_Wnarrowing,
"narrowing conversion of %qE from %qT to %qT "
"inside { }", init, ftype, type);
if (errorcount == savederrorcount)
@@ -959,7 +977,7 @@ check_narrowing (tree type, tree init, tsubst_flags_t complain)
}
}
- return cxx_dialect == cxx98 || ok;
+ return ok;
}
/* Process the initializer INIT for a variable of type TYPE, emitting
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
index 5d803ad..8f14034 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-1.c
@@ -47,3 +47,5 @@ right (int x)
r += -1U >> x;
return r;
}
+
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
index fc89af1..55523a5 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-2.c
@@ -47,3 +47,6 @@ right (int x)
r += -1U >> x;
return r;
}
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
index bf9b1a0..1295b72 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-3.c
@@ -47,3 +47,6 @@ right (int x)
r += -1U >> x;
return r;
}
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c b/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
index 85fbd0e..3088220 100644
--- a/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
+++ b/gcc/testsuite/c-c++-common/Wshift-negative-value-4.c
@@ -47,3 +47,6 @@ right (int x)
r += -1U >> x;
return r;
}
+
+/* { dg-error "not an integer constant" "no constant" { target c++ } 9 } */
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
diff --git a/gcc/testsuite/c-c++-common/fold-bitand-4.c b/gcc/testsuite/c-c++-common/fold-bitand-4.c
index 1b9c388..a658ff1 100644
--- a/gcc/testsuite/c-c++-common/fold-bitand-4.c
+++ b/gcc/testsuite/c-c++-common/fold-bitand-4.c
@@ -1,4 +1,4 @@
-/* { dg-do compile } */
+/* { dg-do compile { target { c } } } */
/* { dg-options "-fdump-tree-original" } */
/* { dg-additional-options "-fno-common" { target hppa*-*-hpux* } } */
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
index 26c9293..a5e3c1f1 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C
@@ -18,7 +18,7 @@ public:
{
/* I am surprised this is considered a constexpr */
return *((Inner *)4);
- } // { dg-error "reinterpret_cast" "" { xfail *-*-* } }
+ } // { dg-error "reinterpret_cast" "" }
};
B B::instance;
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr53792.C b/gcc/testsuite/g++.dg/cpp0x/pr53792.C
new file mode 100644
index 0000000..deb5c1a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr53792.C
@@ -0,0 +1,29 @@
+// PR c++/53792
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -fdump-tree-optimized" }
+// { dg-final { scan-tree-dump "return 0" "optimized" } }
+
+struct entry {
+ char const* label;
+ int value;
+};
+
+constexpr bool same(char const *x, char const *y) {
+ return !*x && !*y ? true
+ : /* default */ (*x == *y && same(x+1, y+1));
+}
+
+constexpr int keyToValue(char const *label, entry const *entries) {
+ return !entries->label ? entries->value
+ : same(entries->label, label) ? entries->value
+ : /*default*/ keyToValue(label, entries+1);
+}
+
+constexpr entry foo[] = {{"Foo", 0}, {"Bar", 1}, {"FooBar", 2}, {0, -1}};
+
+int
+bar()
+{
+ int result = keyToValue("Foo", foo);
+ return result;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp b/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp
new file mode 100644
index 0000000..afa7edb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp
@@ -0,0 +1,14 @@
+// { dg-do compile { target c++11 } }
+
+constexpr int f(void *) { return 0; }
+constexpr int f(...) { return 1; }
+constexpr int g1() { return f(0); }
+constexpr int g2(int n) { return f(n); }
+constexpr int g3(int n) { return f(n*0); }
+
+int main()
+{
+ static_assert(g1() == 0, "g1 failed");
+ static_assert(g2(0) == 1, "g2 failed");
+ static_assert(g3(0) == 1, "g3 failed");
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C b/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C
new file mode 100644
index 0000000..e340de4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -Woverflow" }
+
+#include <climits>
+
+constexpr int f() { return INT_MIN; }
+
+int main()
+{
+ return -f(); // { dg-warning "overflow" }
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C b/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C
new file mode 100644
index 0000000..6b5dff8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-O2 -Woverflow" }
+
+#include <climits>
+
+constexpr int f() { return INT_MAX; }
+
+int main()
+{
+ return f() + 2; // { dg-warning "overflow" }
+}
+
diff --git a/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C
new file mode 100644
index 0000000..39b3557
--- /dev/null
+++ b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -Werror" } */
+
+extern int fl;
+
+#define MAK (fl < 0 ? 1 : (fl ? -1 : 0))
+
+int foo (int sz)
+{
+ if (MAK) return 1;
+ return 0;
+}
+
diff --git a/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C
new file mode 100644
index 0000000..fa91a4f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall -Werror" } */
+
+extern int fl;
+extern int arr[];
+
+#define MAK (fl < 0 ? 1 : (fl ? 2 : 0))
+
+int foo (int sz)
+{
+ unsigned i;
+ int r = 0;
+ for (i = 0; i < MAK; i++)
+ r += arr[i];
+ return r;
+}
+
diff --git a/gcc/testsuite/g++.dg/ext/attr-aligned01.C b/gcc/testsuite/g++.dg/ext/attr-aligned01.C
index c8ec07d..0c5df6d 100644
--- a/gcc/testsuite/g++.dg/ext/attr-aligned01.C
+++ b/gcc/testsuite/g++.dg/ext/attr-aligned01.C
@@ -5,8 +5,8 @@
template<typename T>
void type_alignment(const T&) {
- struct { char c; T t; } s;
- SA((char*)&s.t - (char*)&s.c == 1);
+ struct S { char c; T t; } s;
+ SA(__builtin_offsetof (S,t) - __builtin_offsetof (S,c) == 1);
}
template <class T> struct A { char c; T t; };
@@ -17,7 +17,8 @@ int main() {
A<aligned> a; // { dg-warning "ignoring attributes" }
- SA((char*)&a.t - (char*)&a.c == 1);
+ SA( __builtin_offsetof (__typeof(a),t)
+ - __builtin_offsetof (__typeof(a),c) == 1);
aligned z;
type_alignment(z); // { dg-warning "ignoring attributes" "" { xfail *-*-* } }
diff --git a/gcc/testsuite/g++.dg/ext/offsetof1.C b/gcc/testsuite/g++.dg/ext/offsetof1.C
index 1468c0a..23f3537 100644
--- a/gcc/testsuite/g++.dg/ext/offsetof1.C
+++ b/gcc/testsuite/g++.dg/ext/offsetof1.C
@@ -1,6 +1,7 @@
// PR c++/27601
// Origin: Patrik Hägglund <patrik.hagglund@bredband.net>
// { dg-do compile }
+// { dg-options "-Wno-pointer-arith" }
struct bar {
static int foo;
@@ -10,7 +11,7 @@ struct bar {
int a = __builtin_offsetof(bar, foo); // { dg-error "static data member" }
int av = __builtin_offsetof(volatile bar, foo); // { dg-error "static data member" }
int b = __builtin_offsetof(bar, baz); // { dg-error "member function" }
-int b0 = __builtin_offsetof(bar, baz[0]); // { dg-error "function" }
+int b0 = __builtin_offsetof(bar, baz[0]); // { dg-error "single identifier nor|member function" }
int bv0 = __builtin_offsetof(volatile bar, baz[0]); // { dg-error "function" }
int c = __builtin_offsetof(bar, ~bar); // { dg-error "member function" }
diff --git a/gcc/testsuite/g++.dg/init/const7.C b/gcc/testsuite/g++.dg/init/const7.C
index dbc60b3..e1f31bc 100644
--- a/gcc/testsuite/g++.dg/init/const7.C
+++ b/gcc/testsuite/g++.dg/init/const7.C
@@ -1,9 +1,9 @@
// { dg-do compile }
-// { dg-options "-fdump-tree-gimple" }
+// { dg-options "-fdump-tree-gimple -pedantic" }
struct s { int x, y; };
short offsets[1] = {
- ((char*) &(((struct s*)16)->y) - (char *)16),
+ ((char*) &(((struct s*)16)->y) - (char *)16), // { dg-message "narrowing" "" { target c++11 } }
};
// This ensures that we get a dump whether or not the bug is present.
diff --git a/gcc/testsuite/g++.dg/init/self1.C b/gcc/testsuite/g++.dg/init/self1.C
index dd37c8e..7620833 100644
--- a/gcc/testsuite/g++.dg/init/self1.C
+++ b/gcc/testsuite/g++.dg/init/self1.C
@@ -10,7 +10,7 @@ void f(__SIZE_TYPE__) {
int main()
{
- int* const savepos = sizeof(*savepos) ? 0 : 0;
+ int* const savepos = sizeof(*savepos) ? 0 : 0; /* { dg-error "invalid conversion" "convert" { target c++11 } } */
f (sizeof (*savepos));
diff --git a/gcc/testsuite/g++.dg/other/error22.C b/gcc/testsuite/g++.dg/other/error22.C
index 225dcae..eba0746 100644
--- a/gcc/testsuite/g++.dg/other/error22.C
+++ b/gcc/testsuite/g++.dg/other/error22.C
@@ -5,5 +5,5 @@ extern "C" double fabs (double);
void foo (double x)
{
- fabs (x) (); // { dg-error "__builtin_abs" }
+ fabs (x) (); // { dg-error "function" }
}
diff --git a/gcc/testsuite/g++.dg/other/error24.C b/gcc/testsuite/g++.dg/other/error24.C
index 54343c5..e5e6a4f 100644
--- a/gcc/testsuite/g++.dg/other/error24.C
+++ b/gcc/testsuite/g++.dg/other/error24.C
@@ -8,6 +8,6 @@ void
bar (int i, int j, double k)
{
foo (i && j) (); // { dg-error "\\(\\(?i != 0\\)? \\&\\& \\(?j != 0\\)?\\)" }
- foo (!i || !j) (); // { dg-error "\\(\\(?i == 0\\)? \\|\\| \\(?j == 0\\)?\\)" }
- foo (!i == !j) (); // { dg-error "\\(\\(?i != 0\\)? \\^ \\(?j == 0\\)?\\)" }
+ foo (!i || !j) (); // { dg-error "function" }
+ foo (!i == !j) (); // { dg-error "function" }
}
diff --git a/gcc/testsuite/g++.dg/other/error26.C b/gcc/testsuite/g++.dg/other/error26.C
index fb2c8b7..ffe2728 100644
--- a/gcc/testsuite/g++.dg/other/error26.C
+++ b/gcc/testsuite/g++.dg/other/error26.C
@@ -2,5 +2,5 @@
void foo(__complex__ double x)
{
- __builtin_conj(x)(); // { dg-error "~x" }
+ __builtin_conj(x)(); // { dg-error "function" }
}
diff --git a/gcc/testsuite/g++.dg/parse/array-size2.C b/gcc/testsuite/g++.dg/parse/array-size2.C
index 355ed61..3c83347 100644
--- a/gcc/testsuite/g++.dg/parse/array-size2.C
+++ b/gcc/testsuite/g++.dg/parse/array-size2.C
@@ -14,7 +14,7 @@ extern void bar (char *, char *);
void
foo (void)
{
- char g[(char *) &((struct S *) 0)->b - (char *) 0];
- char h[(__SIZE_TYPE__) &((struct S *) 8)->b];
+ char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" }
+ char h[(__SIZE_TYPE__) &((struct S *) 8)->b]; // { dg-error "constant" "" { xfail *-*-* } }
bar (g, h);
}
diff --git a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
index 946f2e6..8014705 100644
--- a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C
@@ -1,14 +1,10 @@
/* { dg-do compile } */
/* { dg-options "-fsanitize=integer-divide-by-zero" } */
-/* TODO: We expect an error on the invalid case here, because that
- must be a constant-expression. This will be fixed when we have
- proper delayed folding. */
-
void
foo (int i)
{
switch (i)
case 0 * (1 / 0): /* { dg-warning "division by zero" } */
- ; /* { dg-error "division by zero" "" { xfail *-*-* } 10 } */
+ ; /* { dg-error "is not a constant.expression" "" { target *-*-* } 8 } */
}
diff --git a/gcc/testsuite/g++.dg/ubsan/shift-1.C b/gcc/testsuite/g++.dg/ubsan/shift-1.C
index 05e049e..493a55c 100644
--- a/gcc/testsuite/g++.dg/ubsan/shift-1.C
+++ b/gcc/testsuite/g++.dg/ubsan/shift-1.C
@@ -8,10 +8,10 @@ foo (int x)
/* None of the following should pass. */
switch (x)
{
- case 1 >> -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
- case -1 >> -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
- case 1 << -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
- case -1 << -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
+ case 1 >> -1: /* { dg-error "operand of shift" "" } */
+ case -1 >> -1: /* { dg-error "operand of shift" "" } */
+ case 1 << -1: /* { dg-error "operand of shift" "" } */
+ case -1 << -1: /* { dg-error "operand of shift" "" } */
return 1;
}
return 0;
@@ -23,8 +23,8 @@ bar (int x)
/* None of the following should pass. */
switch (x)
{
- case -1 >> 200: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
- case 1 << 200: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */
+ case -1 >> 200: /* { dg-error "operand of shift" "" } */
+ case 1 << 200: /* { dg-error "operand of shift" "" } */
return 1;
}
return 0;
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
index 7cd76e7..a10e15b 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C
@@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
- /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+ /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */
/* Again, overflow in evaluated subexpression. */
@@ -126,3 +126,11 @@ h2i (int x)
ui = INT_MIN;
ui = x ? INT_MIN : 1U;
}
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 32 } */
+/* { dg-warning "invalid conversion from" "convert" { target *-*-* } 56 } */
+/* { dg-warning "invalid conversion from" "convert" { target c++11 } 58 } */
+/* { dg-error "is not a constant expression" "const" { target *-*-* } 65 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 65 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 32 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 32 } */
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
index 73c0e00..c73a28c 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C
@@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
- /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+ /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */
/* Again, overflow in evaluated subexpression. */
@@ -56,7 +56,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" }
/* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* } 55 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-warning "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 58 } */
+/* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */
void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
void
@@ -65,7 +65,7 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
- ;
+ ; /* { dg-error "is not a constant expression" "const" { target *-*-* } 67 } */
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
/* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 69 } */
;
@@ -128,3 +128,9 @@ h2i (int x)
ui = INT_MIN;
ui = x ? INT_MIN : 1U;
}
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 32 } */
+/* { dg-warning "invalid conversion from" "convert" { target c++11 } 60 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 67 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 32 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 32 } */
diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
index 24b3959..23a2585 100644
--- a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
+++ b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C
@@ -17,7 +17,7 @@ enum e {
/* But as in DR#031, the 1/0 in an evaluated subexpression means the
whole expression violates the constraints. */
E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */
- /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */
+ /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */
E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */
/* { dg-error "enumerator value for 'E5' is not an integer constant" "enum error" { target *-*-* } 21 } */
@@ -59,7 +59,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" }
/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */
void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */
-/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 61 } */
+/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 61 } */
void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */
void
@@ -68,7 +68,7 @@ g (int i)
switch (i)
{
case 0 * (1/0): /* { dg-warning "division by zero" } */
- ;
+ ; /* { dg-error "is not a constant expression" "const" { target *-*-* } 70 } */
case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } 72 } */
;
@@ -131,3 +131,9 @@ h2i (int x)
ui = INT_MIN;
ui = x ? INT_MIN : 1U;
}
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */
+/* { dg-error "invalid conversion from" "convert" { target c++11 } 63 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 34 } */
+/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 70 } */
+/* { dg-error "width not an integer constant" "bit.field" { target c++ } 34 } */
+/* { dg-error "is not a constant expression" "division" { target c++ } 34 } */
diff --git a/gcc/testsuite/g++.old-deja/g++.other/null3.C b/gcc/testsuite/g++.old-deja/g++.other/null3.C
index ff1d0669..96691d3 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/null3.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/null3.C
@@ -3,5 +3,5 @@
void x()
{
int* p = 1==0; // { dg-warning "converting 'false' to pointer" "" { target { ! c++11 } } }
-// { dg-error "cannot convert" "" { target c++11 } 5 }
+// { dg-error "cannot convert" "" { target { c++11 } } 5 }
}