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 *ctx = (scope_chain ? scope_chain->fold_map : NULL); + hash_map *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 ; + 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 *); /* 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 *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 bind_expr_stack; struct cp_genericize_omp_taskreg *omp_ctx; tree try_block; + hash_map *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; wtd.p_set = new hash_set; 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 *ctx = (scope_chain ? scope_chain->fold_map : NULL); + hash_map *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 ; + scope_chain->act_cfun = cfun; + } + /* Otherwise if there is no hash_map, use for folding temporary + hash_map. */ + else if (!ctx) + { + hash_map 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 *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 *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 *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 *GTY((skip)) x_local_specializations; + hash_map *GTY((skip)) fold_map; + hash_map *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 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 %"); "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 *fm = scope_chain->fold_map; + hash_map *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 **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 **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 *fm = s->fold_map; + hash_map *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 *fm = scope_chain->fold_map; + hash_map *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 *fm = scope_chain->fold_map; + hash_map *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 &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** 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 + +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 + +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 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 struct A { char c; T t; }; @@ -17,7 +17,8 @@ int main() { A 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 // { 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;