From 415594bb5c49d69f5350401d07abac62bce8656a Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Mon, 8 Feb 2016 10:31:47 -0500 Subject: [PATCH] re PR c++/69631 (Bogus overflow in constant expression error) PR c++/69631 gcc/ * convert.c (convert_to_integer_1): Check dofold on truncation distribution. (convert_to_pointer_maybe_fold, convert_to_real_maybe_fold) (convert_to_integer_maybe_fold, convert_to_complex_maybe_fold): Rename from *_nofold. * convert.h (convert_to_pointer_nofold, convert_to_integer_nofold) (convert_to_real_nofold, convert_to_complex_nofold): New inlines. gcc/cp/ * cp-tree.h (CONV_FOLD, CONV_BACKEND_CONVERT): New. * cvt.c (convert): Pass CONV_BACKEND_CONVERT. (ocp_convert): Use *_maybe_fold. (cp_convert_to_pointer): Add dofold parameter. * cp-gimplify.c (cp_fold) [CONVERT_EXPR]: Call convert. From-SVN: r233216 --- gcc/ChangeLog | 11 +++++++ gcc/convert.c | 37 ++++++++-------------- gcc/convert.h | 17 +++++++--- gcc/cp/ChangeLog | 8 +++++ gcc/cp/cp-gimplify.c | 8 ++++- gcc/cp/cp-tree.h | 2 ++ gcc/cp/cvt.c | 25 ++++++++------- gcc/testsuite/g++.dg/delayedfold/fwrapv1.C | 6 ++++ 8 files changed, 74 insertions(+), 40 deletions(-) create mode 100644 gcc/testsuite/g++.dg/delayedfold/fwrapv1.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 66deab1c410..eef961c8963 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2016-02-08 Jason Merrill + + PR c++/69631 + * convert.c (convert_to_integer_1): Check dofold on truncation + distribution. + (convert_to_pointer_maybe_fold, convert_to_real_maybe_fold) + (convert_to_integer_maybe_fold, convert_to_complex_maybe_fold): + Rename from *_nofold. + * convert.h (convert_to_pointer_nofold, convert_to_integer_nofold) + (convert_to_real_nofold, convert_to_complex_nofold): New inlines. + 2016-02-08 Bernd Schmidt PR rtl-optimization/68730 diff --git a/gcc/convert.c b/gcc/convert.c index dd7d818b67b..dca1d2b67d4 100644 --- a/gcc/convert.c +++ b/gcc/convert.c @@ -105,12 +105,12 @@ convert_to_pointer (tree type, tree expr) } /* A wrapper around convert_to_pointer_1 that only folds the - expression if it is CONSTANT_CLASS_P. */ + expression if DOFOLD, or if it is CONSTANT_CLASS_P. */ tree -convert_to_pointer_nofold (tree type, tree expr) +convert_to_pointer_maybe_fold (tree type, tree expr, bool dofold) { - return convert_to_pointer_1 (type, expr, CONSTANT_CLASS_P (expr)); + return convert_to_pointer_1 (type, expr, dofold || CONSTANT_CLASS_P (expr)); } /* Convert EXPR to some floating-point type TYPE. @@ -403,12 +403,12 @@ convert_to_real (tree type, tree expr) } /* A wrapper around convert_to_real_1 that only folds the - expression if it is CONSTANT_CLASS_P. */ + expression if DOFOLD, or if it is CONSTANT_CLASS_P. */ tree -convert_to_real_nofold (tree type, tree expr) +convert_to_real_maybe_fold (tree type, tree expr, bool dofold) { - return convert_to_real_1 (type, expr, CONSTANT_CLASS_P (expr)); + return convert_to_real_1 (type, expr, dofold || CONSTANT_CLASS_P (expr)); } /* Convert EXPR to some integer (or enum) type TYPE. @@ -669,6 +669,7 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) two narrow values can be combined in their narrow type even to make a wider result--are handled by "shorten" in build_binary_op. */ + if (dofold) switch (ex_form) { case RSHIFT_EXPR: @@ -857,9 +858,6 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) /* 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; @@ -895,7 +893,6 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) 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. */ - if (dofold) return fold_build3 (COND_EXPR, type, TREE_OPERAND (expr, 0), VOID_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 1))) @@ -968,19 +965,13 @@ 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. */ +/* A wrapper around convert_to_complex_1 that only folds the + expression if DOFOLD, or if it is CONSTANT_CLASS_P. */ tree -convert_to_integer_nofold (tree type, tree expr) +convert_to_integer_maybe_fold (tree type, tree expr, bool dofold) { - return convert_to_integer_1 (type, expr, CONSTANT_CLASS_P (expr)); + return convert_to_integer_1 (type, expr, dofold || CONSTANT_CLASS_P (expr)); } /* Convert EXPR to the complex type TYPE in the usual ways. If FOLD_P is @@ -1059,12 +1050,12 @@ convert_to_complex (tree type, tree expr) } /* A wrapper around convert_to_complex_1 that only folds the - expression if it is CONSTANT_CLASS_P. */ + expression if DOFOLD, or if it is CONSTANT_CLASS_P. */ tree -convert_to_complex_nofold (tree type, tree expr) +convert_to_complex_maybe_fold (tree type, tree expr, bool dofold) { - return convert_to_complex_1 (type, expr, CONSTANT_CLASS_P (expr)); + return convert_to_complex_1 (type, expr, dofold || CONSTANT_CLASS_P (expr)); } /* Convert EXPR to the vector type TYPE in the usual ways. */ diff --git a/gcc/convert.h b/gcc/convert.h index aa8fb9b8a02..bee280de78b 100644 --- a/gcc/convert.h +++ b/gcc/convert.h @@ -21,14 +21,23 @@ 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_integer_maybe_fold (tree, tree, bool); extern tree convert_to_pointer (tree, tree); -extern tree convert_to_pointer_nofold (tree, tree); +extern tree convert_to_pointer_maybe_fold (tree, tree, bool); extern tree convert_to_real (tree, tree); -extern tree convert_to_real_nofold (tree, tree); +extern tree convert_to_real_maybe_fold (tree, tree, bool); 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_complex_maybe_fold (tree, tree, bool); extern tree convert_to_vector (tree, tree); +extern inline tree convert_to_integer_nofold (tree t, tree x) +{ return convert_to_integer_maybe_fold (t, x, false); } +extern inline tree convert_to_pointer_nofold (tree t, tree x) +{ return convert_to_pointer_maybe_fold (t, x, false); } +extern inline tree convert_to_real_nofold (tree t, tree x) +{ return convert_to_real_maybe_fold (t, x, false); } +extern inline tree convert_to_complex_nofold (tree t, tree x) +{ return convert_to_complex_maybe_fold (t, x, false); } + #endif /* GCC_CONVERT_H */ diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 427425ae17a..470d82536f4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,11 @@ +2016-02-08 Jason Merrill + + * cp-tree.h (CONV_FOLD, CONV_BACKEND_CONVERT): New. + * cvt.c (convert): Pass CONV_BACKEND_CONVERT. + (ocp_convert): Use *_maybe_fold. + (cp_convert_to_pointer): Add dofold parameter. + * cp-gimplify.c (cp_fold) [CONVERT_EXPR]: Call convert. + 2016-02-05 Martin Sebor PR c++/69662 diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index bb815340ddd..d83e9deed07 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -1953,7 +1953,13 @@ cp_fold (tree x) loc = EXPR_LOCATION (x); op0 = cp_fold_maybe_rvalue (TREE_OPERAND (x, 0), rval_ops); - if (op0 != TREE_OPERAND (x, 0)) + if (code == CONVERT_EXPR + && SCALAR_TYPE_P (TREE_TYPE (x)) + && op0 != void_node) + /* During parsing we used convert_to_*_nofold; re-convert now using the + folding variants, since fold() doesn't do those transformations. */ + x = fold (convert (TREE_TYPE (x), op0)); + else if (op0 != TREE_OPERAND (x, 0)) { if (op0 == error_mark_node) x = error_mark_node; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 0aeee578f7e..786927b51ac 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5019,10 +5019,12 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, TYPENAME_FLAG }; #define CONV_PRIVATE 16 /* #define CONV_NONCONVERTING 32 */ #define CONV_FORCE_TEMP 64 +#define CONV_FOLD 128 #define CONV_OLD_CONVERT (CONV_IMPLICIT | CONV_STATIC | CONV_CONST \ | CONV_REINTERPRET) #define CONV_C_CAST (CONV_IMPLICIT | CONV_STATIC | CONV_CONST \ | CONV_REINTERPRET | CONV_PRIVATE | CONV_FORCE_TEMP) +#define CONV_BACKEND_CONVERT (CONV_OLD_CONVERT | CONV_FOLD) /* Used by build_expr_type_conversion to indicate which types are acceptable as arguments to the expression under consideration. */ diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index f381f9b3800..60362fd73c4 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -34,7 +34,6 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "convert.h" -static tree cp_convert_to_pointer (tree, tree, tsubst_flags_t); static tree convert_to_pointer_force (tree, tree, tsubst_flags_t); static tree build_type_conversion (tree, tree); static tree build_up_reference (tree, tree, int, tree, tsubst_flags_t); @@ -50,7 +49,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[_nofold]. + In convert.c, convert_to_integer[_maybe_fold]. 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. @@ -70,7 +69,8 @@ static void diagnose_ref_binding (location_t, tree, tree, tree); else try C-style pointer conversion. */ static tree -cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain) +cp_convert_to_pointer (tree type, tree expr, bool dofold, + tsubst_flags_t complain) { tree intype = TREE_TYPE (expr); enum tree_code form; @@ -185,7 +185,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain) { if (TREE_CODE (expr) == PTRMEM_CST) return cp_convert_to_pointer (type, PTRMEM_CST_MEMBER (expr), - complain); + dofold, complain); else if (TREE_CODE (expr) == OFFSET_REF) { tree object = TREE_OPERAND (expr, 0); @@ -237,7 +237,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_nofold (type, expr); + return convert_to_pointer_maybe_fold (type, expr, dofold); } if (type_unknown_p (expr)) @@ -296,7 +296,7 @@ convert_to_pointer_force (tree type, tree expr, tsubst_flags_t complain) } } - return cp_convert_to_pointer (type, expr, complain); + return cp_convert_to_pointer (type, expr, /*fold*/false, complain); } /* We are passing something to a function which requires a reference. @@ -670,6 +670,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags, const char *invalid_conv_diag; tree e1; location_t loc = EXPR_LOC_OR_LOC (expr, input_location); + bool dofold = (convtype & CONV_FOLD); if (error_operand_p (e) || type == error_mark_node) return error_mark_node; @@ -706,7 +707,7 @@ 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 convert_to_complex_nofold (type, e); + return convert_to_complex_maybe_fold (type, e, dofold); else if (VECTOR_TYPE_P (type)) return convert_to_vector (type, e); else if (TREE_CODE (e) == TARGET_EXPR) @@ -799,7 +800,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags, return cp_truthvalue_conversion (e); } - converted = convert_to_integer_nofold (type, e); + converted = convert_to_integer_maybe_fold (type, e, dofold); /* Ignore any integer overflow caused by the conversion. */ return ignore_overflows (converted, e); @@ -811,7 +812,7 @@ ocp_convert (tree type, tree expr, int convtype, int flags, return nullptr_node; } if (POINTER_TYPE_P (type) || TYPE_PTRMEM_P (type)) - return cp_convert_to_pointer (type, e, complain); + return cp_convert_to_pointer (type, e, dofold, complain); if (code == VECTOR_TYPE) { tree in_vtype = TREE_TYPE (e); @@ -842,9 +843,9 @@ ocp_convert (tree type, tree expr, int convtype, int flags, TREE_TYPE (e)); } if (code == REAL_TYPE) - return convert_to_real_nofold (type, e); + return convert_to_real_maybe_fold (type, e, dofold); else if (code == COMPLEX_TYPE) - return convert_to_complex_nofold (type, e); + return convert_to_complex_maybe_fold (type, e, dofold); } /* New C++ semantics: since assignment is now based on @@ -1460,7 +1461,7 @@ convert (tree type, tree expr) if (POINTER_TYPE_P (type) && POINTER_TYPE_P (intype)) return build_nop (type, expr); - return ocp_convert (type, expr, CONV_OLD_CONVERT, + return ocp_convert (type, expr, CONV_BACKEND_CONVERT, LOOKUP_NORMAL|LOOKUP_NO_CONVERSION, tf_warning_or_error); } diff --git a/gcc/testsuite/g++.dg/delayedfold/fwrapv1.C b/gcc/testsuite/g++.dg/delayedfold/fwrapv1.C new file mode 100644 index 00000000000..412535ce1ee --- /dev/null +++ b/gcc/testsuite/g++.dg/delayedfold/fwrapv1.C @@ -0,0 +1,6 @@ +// PR c++/69631 +// { dg-options -fwrapv } + +struct C { + static const unsigned short max = static_cast((32767 * 2 + 1)); +};