diff options
46 files changed, 1165 insertions, 318 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 52f95a0..2ea5448 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,65 @@ +2015-11-13 Kai Tietz <ktietz70@googlemail.com> + Marek Polacek <polacek@redhat.com> + Jason Merrill <jason@redhat.com> + + * call.c (build_conditional_expr_1, convert_like_real) + (convert_arg_to_ellipsis, convert_for_arg_passing): Don't fold. + (build_new_op_1, build_over_call, build_cxx_call): Fold for warnings. + * class.c (build_base_path, determine_primary_bases) + (update_vtable_entry_for_fn, check_bitfield_decl) + (layout_nonempty_base_or_field, layout_empty_base) + (propagate_binfo_offsets, include_empty_classes) + (layout_class_type, build_vbase_offset_vtbl_entries): Use + fold_convert. + * constexpr.c (cxx_eval_builtin_function_call): Fold away the NOP_EXPR. + (cxx_eval_call_expression): Handle MEM_REF. + (cxx_eval_pointer_plus_expression): Fold the second operand. + (cxx_eval_constant_expression): Handle MEM_REF, UNARY_PLUS_EXPR. + (fold_simple_1, fold_simple): New. + (maybe_constant_value_1): Factor out from maybe_constant_value. + (cv_cache, maybe_constant_value): Cache results. + (maybe_constant_init): Handle null input. + (potential_constant_expression_1): Handle RESULT_DECL, EMPTY_CLASS_EXPR. + * cp-array-notation.c (build_array_notation_ref): Fold operands. + * cp-gimplify.c (cp_fold_r, cp_fold): New. + (cp_genericize_r): Use fold_convert. Don't fold SIZEOF_EXPR. + (cp_genericize): Fold everything. + (contains_label_1, contains_label_p): New. + (cp_fold, cp_fully_fold): New. + * cp-tree.h (class cache_map): New. + * cvt.c (cp_convert_to_pointer, ocp_convert): Use convert_to_*_nofold. + (cp_convert_and_check): Use cp_fully_fold. + (convert, convert_force): Don't fold. + * decl.c (fold_sizeof_expr): Change from fold_sizeof_expr_r. + (compute_array_index_type): Use cp_fully_fold. + (build_enumerator): Use fold_convert. + * decl2.c (get_guard_cond, set_guard): Use fold_convert. + * init.c (build_zero_init_1): Fold zero-initializers. + (build_new_1): Fold nelts calculations. + (build_vec_delete_1): Fold conversions. + (build_vec_init): Fold maxindex. + * parser.c (cp_parser_binary_expression): Fold LHS of || and &&. + (cp_parser_question_colon_clause): Fold LHS. + * pt.c (convert_nontype_argument): Fold nullptr conversion. + * semantics.c (finish_unary_op_expr): Fold for warnings. + (handle_omp_array_sections_1): Fold length and low bound. + (handle_omp_for_class_iterator): Fold various things. + * tree.c (builtin_valid_in_constant_expr_p): Add + BUILT_IN_ATOMIC_ALWAYS_LOCK_FREE. + (convert_bitfield_to_declared_type): Don't fold. + (handle_init_priority_attribute): Fold. + (fold_if_not_in_template): Remove. + * typeck.c (decay_conversion, build_class_member_access_expr) + (build_simple_component_ref, cp_build_array_ref, build_vec_cmp) + (cp_pointer_int_sum, pointer_diff): Don't fold. + (cp_build_binary_op): Fold for warnings and PMF ops. + (cp_build_unary_op): Fold negation of a constant, nothing else. + (expand_ptrmemfunc_cst): Fold operations. + * typeck2.c (split_nonconstant_init): Fold initializer. + (store_init_value): Likewise. + (check_narrowing): Try folding. + * config-lang.in (gtfiles): Add cp-gimplify.c. + 2015-11-13 David Malcolm <dmalcolm@redhat.com> * error.c (pedwarn_cxx98): Pass line_table to rich_location ctor. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index a860e46..77c2936 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4748,7 +4748,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] @@ -5152,9 +5152,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. */ @@ -5690,8 +5687,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); } @@ -5729,7 +5726,8 @@ 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: @@ -5740,9 +5738,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: @@ -6496,7 +6495,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), @@ -6737,7 +6736,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; @@ -6982,7 +6981,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) ; @@ -7502,7 +7501,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. */ @@ -7693,7 +7704,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); @@ -7705,9 +7715,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 @@ -7741,17 +7760,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 866e342..216a301 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -421,7 +421,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 @@ -554,8 +554,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. */ @@ -1847,9 +1845,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); @@ -1911,7 +1909,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); } @@ -2635,7 +2633,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) { @@ -2643,7 +2641,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) @@ -2732,8 +2730,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, @@ -2745,9 +2743,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); @@ -3469,7 +3467,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; } @@ -4314,8 +4312,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)))); } @@ -4362,7 +4360,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, @@ -5976,9 +5974,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. */ @@ -6183,7 +6181,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))); @@ -6457,7 +6455,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))), @@ -6466,7 +6464,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); @@ -9302,7 +9300,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/config-lang.in b/gcc/cp/config-lang.in index 357abdc..ba841df 100644 --- a/gcc/cp/config-lang.in +++ b/gcc/cp/config-lang.in @@ -29,4 +29,4 @@ compilers="cc1plus\$(exeext)" target_libs="target-libstdc++-v3" -gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c \$(srcdir)/cp/constexpr.c" +gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/cp-lang.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c \$(srcdir)/cp/constexpr.c \$(srcdir)/cp/cp-gimplify.c" diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 159c4b3..aabb980 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1035,6 +1035,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; @@ -1275,6 +1277,16 @@ 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. ??? we could still optimize away the + call. */ + 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, @@ -2540,6 +2552,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); @@ -3073,6 +3096,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] */ @@ -3333,6 +3358,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); @@ -3370,17 +3396,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; @@ -3538,8 +3554,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); @@ -3559,11 +3578,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. */ @@ -3831,12 +3853,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; @@ -3862,6 +3958,24 @@ maybe_constant_value (tree t, tree decl) return r; } +static GTY((cache, deletable)) cache_map cv_cache; + +/* 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 = cv_cache.get (t); + if (!ret) + { + ret = maybe_constant_value_1 (t, decl); + cv_cache.put (t, ret); + } + return ret; +} + /* Like maybe_constant_value but first fully instantiate the argument. Note: this is equivalent to instantiate_non_dependent_expr_sfinae @@ -3927,6 +4041,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 @@ -4037,6 +4153,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: @@ -4625,6 +4742,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 d445054..84d7925 100644 --- a/gcc/cp/cp-array-notation.c +++ b/gcc/cp/cp-array-notation.c @@ -1380,7 +1380,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 2b77e75..5f5cd36 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -36,7 +36,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); /* Local declarations. */ @@ -914,6 +916,71 @@ struct cp_genericize_data 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; + enum tree_code code; + + *stmt_p = stmt = cp_fold (*stmt_p); + + 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. */ @@ -973,7 +1040,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 @@ -1288,22 +1355,6 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) || TREE_CODE (stmt) == OMP_DISTRIBUTE || TREE_CODE (stmt) == OMP_TASKLOOP) genericize_omp_for_stmt (stmt_p, walk_subtrees, data); - else if (TREE_CODE (stmt) == SIZEOF_EXPR) - { - if (SIZEOF_EXPR_TYPE_P (stmt)) - *stmt_p - = cxx_sizeof_or_alignof_type (TREE_TYPE (TREE_OPERAND (stmt, 0)), - SIZEOF_EXPR, false); - else if (TYPE_P (TREE_OPERAND (stmt, 0))) - *stmt_p = cxx_sizeof_or_alignof_type (TREE_OPERAND (stmt, 0), - SIZEOF_EXPR, false); - else - *stmt_p = cxx_sizeof_or_alignof_expr (TREE_OPERAND (stmt, 0), - SIZEOF_EXPR, false); - if (*stmt_p == error_mark_node) - *stmt_p = size_one_node; - return NULL; - } else if ((flag_sanitize & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_VPTR)) && !wtd->no_sanitize_p) @@ -1414,6 +1465,10 @@ cp_genericize (tree fndecl) { tree t; + /* Fold ALL the trees! FIXME we should be able to remove this, but + apparently that still causes optimization regressions. */ + cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, NULL, NULL); + /* Fix up the types of parms passed by invisible reference. */ for (t = DECL_ARGUMENTS (fndecl); t; t = DECL_CHAIN (t)) if (TREE_ADDRESSABLE (TREE_TYPE (t))) @@ -1777,3 +1832,402 @@ 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) +{ + return cp_fold (x); +} + +static GTY((cache, deletable)) cache_map fold_cache; + +/* This function tries to fold an expression X. + To avoid combinatorial explosion, folding results are kept in fold_cache. + If we are processing a template or X is invalid, we don't fold at all. + For performance reasons we don't cache expressions representing a + declaration or constant. + Function returns X or its folded variant. */ + +static tree +cp_fold (tree x) +{ + tree op0, op1, op2, op3; + tree org_x = x, r = NULL_TREE; + enum tree_code code; + location_t loc; + + if (!x || error_operand_p (x)) + return x; + + if (processing_template_decl + || (EXPR_P (x) && !TREE_TYPE (x))) + return x; + + /* Don't bother to cache DECLs or constants. */ + if (DECL_P (x) || CONSTANT_CLASS_P (x)) + return x; + + if (tree cached = fold_cache.get (x)) + return cached; + + 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: + case NON_LVALUE_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); + + 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 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 INDIRECT_REF: + + loc = EXPR_LOCATION (x); + op0 = cp_fold (TREE_OPERAND (x, 0)); + + 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)); + op1 = cp_fold (TREE_OPERAND (x, 1)); + + 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)); + op1 = cp_fold (TREE_OPERAND (x, 1)); + 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)); + + if (TREE_SIDE_EFFECTS (op0)) + break; + + op1 = cp_fold (TREE_OPERAND (x, 1)); + op2 = cp_fold (TREE_OPERAND (x, 2)); + + 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); + break; + } + + x = copy_node (x); + + m = call_expr_nargs (x); + for (i = 0; i < m; i++) + { + r = cp_fold (CALL_EXPR_ARG (x, i)); + 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); + 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 CONSTRUCTOR: + { + unsigned i; + constructor_elt *p; + vec<constructor_elt, va_gc> *elts = CONSTRUCTOR_ELTS (x); + FOR_EACH_VEC_SAFE_ELT (elts, i, p) + p->value = cp_fold (p->value); + break; + } + case TREE_VEC: + { + bool changed = false; + vec<tree, va_gc> *vec = make_tree_vector (); + int i, n = TREE_VEC_LENGTH (x); + vec_safe_reserve (vec, n); + + for (i = 0; i < n; i++) + { + tree op = cp_fold (TREE_VEC_ELT (x, i)); + 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)); + op1 = cp_fold (TREE_OPERAND (x, 1)); + op2 = cp_fold (TREE_OPERAND (x, 2)); + op3 = cp_fold (TREE_OPERAND (x, 3)); + + 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; + + default: + return org_x; + } + + fold_cache.put (org_x, x); + /* Prevent that we try to fold an already folded result again. */ + if (x != org_x) + fold_cache.put (x, x); + + return x; +} + +#include "gt-cp-cp-gimplify.h" diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 828f268..84437b4 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5447,6 +5447,42 @@ extern cp_parameter_declarator *no_parameters; /* True if we saw "#pragma GCC java_exceptions". */ extern bool pragma_java_exceptions; +/* Data structure for a mapping from tree to tree that's only used as a cache; + we don't GC-mark trees in the map, and we clear the map when collecting + garbage. Global variables of this type must be marked + GTY((cache,deletable)) so that the gt_cleare_cache function is called by + ggc_collect but we don't try to load the map pointer from a PCH. + + FIXME improve to use keep_cache_entry. */ +class cache_map +{ + /* Use a lazily initialized pointer rather than a map member since a + hash_map can't be constructed in a static initializer. */ + hash_map<tree, tree> *map; + +public: + tree get (tree key) + { + if (map) + if (tree *slot = map->get (key)) + return *slot; + return NULL_TREE; + } + + bool put (tree key, tree val) + { + if (!map) + map = new hash_map<tree, tree>; + return map->put (key, val); + } + + friend inline void gt_cleare_cache (cache_map &cm) + { + if (cm.map) + cm.map->empty(); + } +}; + /* in call.c */ extern bool check_dtor_name (tree, tree); bool magic_varargs_p (tree); @@ -6474,7 +6510,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 +6740,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 +6832,14 @@ extern tree cxx_constant_value (tree, tree = NULL_TREE); extern tree maybe_constant_value (tree, tree = NULL_TREE); extern tree maybe_constant_init (tree, tree = NULL_TREE); extern tree fold_non_dependent_expr (tree); +extern tree fold_simple (tree); extern bool is_sub_constant_expr (tree); extern bool reduced_constant_expression_p (tree); extern bool is_instantiation_of_constexpr (tree); extern bool var_in_constexpr_fn (tree); extern void explain_invalid_constexpr_fn (tree); extern vec<tree> cx_error_context (void); +extern tree fold_sizeof_expr (tree); /* In c-family/cilk.c */ extern bool cilk_valid_spawn (tree); diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index c6e13f3..0231efc 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -50,7 +50,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. @@ -237,7 +237,7 @@ cp_convert_to_pointer (tree type, tree expr, tsubst_flags_t complain) gcc_assert (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (expr))) == GET_MODE_SIZE (TYPE_MODE (type))); - return convert_to_pointer (type, expr); + return convert_to_pointer_nofold (type, expr); } if (type_unknown_p (expr)) @@ -630,22 +630,25 @@ 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) && c_inhibit_evaluation_warnings == 0) { - tree folded = maybe_constant_value (expr); - tree stripped = folded; - tree 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. */ - STRIP_NOPS (stripped); - - if (!TREE_OVERFLOW_P (stripped) + tree folded = cp_fully_fold (expr); + tree folded_result; + if (folded == expr) + folded_result = result; + else + { + /* Avoid bogus -Wparentheses warnings. */ + TREE_NO_WARNING (folded) = true; + folded_result = cp_convert (type, folded, tf_none); + } + folded_result = fold_simple (folded_result); + if (!TREE_OVERFLOW_P (folded) && folded_result != error_mark_node) warnings_for_convert_and_check (input_location, type, folded, folded_result); @@ -703,9 +706,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 @@ -718,7 +721,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); } } @@ -796,7 +799,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); @@ -808,7 +811,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); @@ -823,7 +826,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) { @@ -839,9 +842,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 @@ -1454,7 +1457,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, @@ -1472,13 +1475,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 383b47d..675342e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -8589,33 +8589,24 @@ 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. */ +/* Reduce a SIZEOF_EXPR to its value. */ -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; +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; } /* Given the SIZE (i.e., number of elements) in an array, compute an @@ -8708,7 +8699,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) { @@ -8795,7 +8797,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)) @@ -8803,18 +8805,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 @@ -13514,7 +13504,7 @@ incremented enumerator value is too large for %<long%>"); "type %<%T%>", value, ENUM_UNDERLYING_TYPE (enumtype)); /* Convert the value to the appropriate type. */ - value = convert (ENUM_UNDERLYING_TYPE (enumtype), value); + value = fold_convert (ENUM_UNDERLYING_TYPE (enumtype), value); } } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 149f8a1..47c9ec9 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -3112,7 +3112,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); @@ -3120,7 +3120,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); @@ -3138,7 +3138,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); } diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 9e582d6..fccd289 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -175,9 +175,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; @@ -2558,6 +2558,11 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, outer_nelts_from_type = true; } + /* Lots of logic below. depends on whether we have a constant number of + elements, so go ahead and fold it now. */ + if (outer_nelts) + outer_nelts = maybe_constant_value (outer_nelts); + /* If our base type is an array, then make sure we know how many elements it has. */ for (elt_type = type; @@ -2608,7 +2613,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, /* Warn if we performed the (T[N]) to T[N] transformation and N is variable. */ if (outer_nelts_from_type - && !TREE_CONSTANT (maybe_constant_value (outer_nelts))) + && !TREE_CONSTANT (outer_nelts)) { if (complain & tf_warning_or_error) { @@ -2708,7 +2713,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, max_outer_nelts = wi::udiv_trunc (max_size, inner_size); 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)); if (TREE_CONSTANT (outer_nelts)) { @@ -2897,7 +2902,7 @@ build_new_1 (vec<tree, va_gc> **placement, tree type, tree nelts, { placement_expr = get_target_expr (placement_first); CALL_EXPR_ARG (alloc_call, 1) - = convert (TREE_TYPE (placement), placement_expr); + = fold_convert (TREE_TYPE (placement), placement_expr); } if (!member_new_p @@ -3506,7 +3511,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 @@ -3549,7 +3554,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 */ @@ -3595,8 +3600,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); @@ -3718,6 +3723,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); @@ -3759,6 +3765,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/parser.c b/gcc/cp/parser.c index 0c918ecf..4ca7983 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -6778,7 +6778,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. */ @@ -8522,9 +8522,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. */ @@ -8571,9 +8573,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 @@ -8659,7 +8663,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; @@ -8674,7 +8678,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 @@ -8682,11 +8687,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; } @@ -8694,7 +8700,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, diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index f3b0cd0..2904657 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -6211,7 +6211,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 db37e85..67f8590 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2562,9 +2562,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; } @@ -4476,6 +4493,11 @@ handle_omp_array_sections_1 (tree c, tree t, vec<tree> &types, low_bound = mark_rvalue_use (low_bound); if (length) length = mark_rvalue_use (length); + /* We need to reduce to real constant-values for checks below. */ + if (length) + length = fold_simple (length); + if (low_bound) + low_bound = fold_simple (low_bound); if (low_bound && TREE_CODE (low_bound) == INTEGER_CST && TYPE_PRECISION (TREE_TYPE (low_bound)) @@ -7440,6 +7462,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: @@ -7475,6 +7498,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) @@ -7536,7 +7560,7 @@ 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 diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index bd5caf7..d2db31a 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -303,9 +303,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. */ @@ -681,8 +691,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; } @@ -3479,10 +3489,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; } @@ -4257,26 +4270,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 90c95fb..6541e97c 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1945,8 +1945,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; @@ -2439,7 +2437,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 @@ -2852,9 +2849,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 @@ -3173,8 +3170,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); @@ -3921,7 +3917,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); } @@ -3976,7 +3971,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 @@ -4599,7 +4594,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 { @@ -4640,10 +4635,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 @@ -4997,10 +4994,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; } @@ -5028,20 +5022,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) @@ -5060,9 +5046,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); } @@ -5117,18 +5103,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; } @@ -5178,8 +5176,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. @@ -5255,7 +5252,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 @@ -5771,6 +5768,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; @@ -5835,10 +5836,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: @@ -6005,7 +6003,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) @@ -6999,7 +6997,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))) { @@ -7027,7 +7025,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))) @@ -7038,13 +7036,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) @@ -7896,8 +7894,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 @@ -8078,41 +8075,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 cfc76c4..839091c 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -738,6 +738,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; @@ -828,6 +829,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags) DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = const_init; TREE_CONSTANT (decl) = const_init && decl_maybe_constant_var_p (decl); } + value = cp_fully_fold (value); if (cxx_dialect >= cxx14 && CLASS_TYPE_P (strip_array_types (type))) /* Handle aggregate NSDMI in non-constant initializers, too. */ @@ -926,19 +928,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; } } @@ -946,7 +964,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) @@ -955,7 +973,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/objcp/ChangeLog b/gcc/objcp/ChangeLog index 999d57a..7bec630 100644 --- a/gcc/objcp/ChangeLog +++ b/gcc/objcp/ChangeLog @@ -1,3 +1,7 @@ +2015-11-13 Jason Merrill <jason@redhat.com> + + * config-lang.in (gtfiles): Add cp-gimplify.c. + 2015-11-11 Andrew MacLeod <amacleod@redhat.com> * objcp-decl.c: Remove unused header files. diff --git a/gcc/objcp/config-lang.in b/gcc/objcp/config-lang.in index 9b2cea7..5f3f4e0 100644 --- a/gcc/objcp/config-lang.in +++ b/gcc/objcp/config-lang.in @@ -45,6 +45,6 @@ subdir_requires="objc cp" # This list is separated in two parts: the first one is identical to # the C++ one, the second one contains our ObjC++ additions. -gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c \$(srcdir)/cp/constexpr.c \ +gtfiles="\$(srcdir)/cp/rtti.c \$(srcdir)/cp/mangle.c \$(srcdir)/cp/name-lookup.h \$(srcdir)/cp/name-lookup.c \$(srcdir)/cp/cp-tree.h \$(srcdir)/cp/decl.h \$(srcdir)/cp/call.c \$(srcdir)/cp/decl.c \$(srcdir)/cp/decl2.c \$(srcdir)/cp/pt.c \$(srcdir)/cp/repo.c \$(srcdir)/cp/semantics.c \$(srcdir)/cp/tree.c \$(srcdir)/cp/parser.h \$(srcdir)/cp/parser.c \$(srcdir)/cp/method.c \$(srcdir)/cp/typeck2.c \$(srcdir)/c-family/c-common.c \$(srcdir)/c-family/c-common.h \$(srcdir)/c-family/c-objc.h \$(srcdir)/c-family/c-lex.c \$(srcdir)/c-family/c-pragma.h \$(srcdir)/c-family/c-pragma.c \$(srcdir)/cp/class.c \$(srcdir)/cp/cp-objcp-common.c \$(srcdir)/cp/except.c \$(srcdir)/cp/vtable-class-hierarchy.c \$(srcdir)/cp/constexpr.c \$(srcdir)/cp/cp-gimplify.c \ \$(srcdir)/objc/objc-map.h \$(srcdir)/objc/objc-act.h \$(srcdir)/objc/objc-act.c \$(srcdir)/objc/objc-runtime-shared-support.c \$(srcdir)/objc/objc-gnu-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-01.c \$(srcdir)/objc/objc-next-runtime-abi-02.c \$(srcdir)/c-family/c-cppbuiltin.c" 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..55523a53 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 1b9c3885..a658ff1 100644 --- a/gcc/testsuite/c-c++-common/fold-bitand-4.c +++ b/gcc/testsuite/c-c++-common/fold-bitand-4.c @@ -1,4 +1,4 @@ -/* { dg-do compile } */ +/* { dg-do compile { target { c } } } */ /* { dg-options "-fdump-tree-original" } */ /* { dg-additional-options "-fno-common" { target hppa*-*-hpux* } } */ diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C index 26c9293..a5e3c1f1 100644 --- a/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-reinterpret1.C @@ -18,7 +18,7 @@ public: { /* I am surprised this is considered a constexpr */ return *((Inner *)4); - } // { dg-error "reinterpret_cast" "" { xfail *-*-* } } + } // { dg-error "reinterpret_cast" "" } }; B B::instance; diff --git a/gcc/testsuite/g++.dg/cpp0x/pr53792.C b/gcc/testsuite/g++.dg/cpp0x/pr53792.C new file mode 100644 index 0000000..deb5c1a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr53792.C @@ -0,0 +1,29 @@ +// PR c++/53792 +// { dg-do compile { target c++11 } } +// { dg-options "-O2 -fdump-tree-optimized" } +// { dg-final { scan-tree-dump "return 0" "optimized" } } + +struct entry { + char const* label; + int value; +}; + +constexpr bool same(char const *x, char const *y) { + return !*x && !*y ? true + : /* default */ (*x == *y && same(x+1, y+1)); +} + +constexpr int keyToValue(char const *label, entry const *entries) { + return !entries->label ? entries->value + : same(entries->label, label) ? entries->value + : /*default*/ keyToValue(label, entries+1); +} + +constexpr entry foo[] = {{"Foo", 0}, {"Bar", 1}, {"FooBar", 2}, {0, -1}}; + +int +bar() +{ + int result = keyToValue("Foo", foo); + return result; +} diff --git a/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp b/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp new file mode 100644 index 0000000..afa7edb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/pr56868.cpp @@ -0,0 +1,14 @@ +// { dg-do compile { target c++11 } } + +constexpr int f(void *) { return 0; } +constexpr int f(...) { return 1; } +constexpr int g1() { return f(0); } +constexpr int g2(int n) { return f(n); } +constexpr int g3(int n) { return f(n*0); } + +int main() +{ + static_assert(g1() == 0, "g1 failed"); + static_assert(g2(0) == 1, "g2 failed"); + static_assert(g3(0) == 1, "g3 failed"); +} diff --git a/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C b/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C new file mode 100644 index 0000000..e340de4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/warn-ovl1.C @@ -0,0 +1,12 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-O2 -Woverflow" } + +#include <climits> + +constexpr int f() { return INT_MIN; } + +int main() +{ + return -f(); // { dg-warning "overflow" } +} + diff --git a/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C b/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C new file mode 100644 index 0000000..6b5dff8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/warn-ovl2.C @@ -0,0 +1,12 @@ +// { dg-do compile { target c++11 } } +// { dg-options "-O2 -Woverflow" } + +#include <climits> + +constexpr int f() { return INT_MAX; } + +int main() +{ + return f() + 2; // { dg-warning "overflow" } +} + diff --git a/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C new file mode 100644 index 0000000..39b3557 --- /dev/null +++ b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned1.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -Werror" } */ + +extern int fl; + +#define MAK (fl < 0 ? 1 : (fl ? -1 : 0)) + +int foo (int sz) +{ + if (MAK) return 1; + return 0; +} + diff --git a/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C new file mode 100644 index 0000000..fa91a4f --- /dev/null +++ b/gcc/testsuite/g++.dg/delayedfold/df-warn-signedunsigned2.C @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-Wall -Werror" } */ + +extern int fl; +extern int arr[]; + +#define MAK (fl < 0 ? 1 : (fl ? 2 : 0)) + +int foo (int sz) +{ + unsigned i; + int r = 0; + for (i = 0; i < MAK; i++) + r += arr[i]; + return r; +} + diff --git a/gcc/testsuite/g++.dg/ext/attr-aligned01.C b/gcc/testsuite/g++.dg/ext/attr-aligned01.C index c8ec07d..0c5df6d 100644 --- a/gcc/testsuite/g++.dg/ext/attr-aligned01.C +++ b/gcc/testsuite/g++.dg/ext/attr-aligned01.C @@ -5,8 +5,8 @@ template<typename T> void type_alignment(const T&) { - struct { char c; T t; } s; - SA((char*)&s.t - (char*)&s.c == 1); + struct S { char c; T t; } s; + SA(__builtin_offsetof (S,t) - __builtin_offsetof (S,c) == 1); } template <class T> struct A { char c; T t; }; @@ -17,7 +17,8 @@ int main() { A<aligned> a; // { dg-warning "ignoring attributes" } - SA((char*)&a.t - (char*)&a.c == 1); + SA( __builtin_offsetof (__typeof(a),t) + - __builtin_offsetof (__typeof(a),c) == 1); aligned z; type_alignment(z); // { dg-warning "ignoring attributes" "" { xfail *-*-* } } diff --git a/gcc/testsuite/g++.dg/ext/offsetof1.C b/gcc/testsuite/g++.dg/ext/offsetof1.C index 1468c0a..23f3537 100644 --- a/gcc/testsuite/g++.dg/ext/offsetof1.C +++ b/gcc/testsuite/g++.dg/ext/offsetof1.C @@ -1,6 +1,7 @@ // PR c++/27601 // Origin: Patrik Hägglund <patrik.hagglund@bredband.net> // { dg-do compile } +// { dg-options "-Wno-pointer-arith" } struct bar { static int foo; @@ -10,7 +11,7 @@ struct bar { int a = __builtin_offsetof(bar, foo); // { dg-error "static data member" } int av = __builtin_offsetof(volatile bar, foo); // { dg-error "static data member" } int b = __builtin_offsetof(bar, baz); // { dg-error "member function" } -int b0 = __builtin_offsetof(bar, baz[0]); // { dg-error "function" } +int b0 = __builtin_offsetof(bar, baz[0]); // { dg-error "single identifier nor|member function" } int bv0 = __builtin_offsetof(volatile bar, baz[0]); // { dg-error "function" } int c = __builtin_offsetof(bar, ~bar); // { dg-error "member function" } diff --git a/gcc/testsuite/g++.dg/init/const7.C b/gcc/testsuite/g++.dg/init/const7.C index dbc60b3..e1f31bc 100644 --- a/gcc/testsuite/g++.dg/init/const7.C +++ b/gcc/testsuite/g++.dg/init/const7.C @@ -1,9 +1,9 @@ // { dg-do compile } -// { dg-options "-fdump-tree-gimple" } +// { dg-options "-fdump-tree-gimple -pedantic" } struct s { int x, y; }; short offsets[1] = { - ((char*) &(((struct s*)16)->y) - (char *)16), + ((char*) &(((struct s*)16)->y) - (char *)16), // { dg-message "narrowing" "" { target c++11 } } }; // This ensures that we get a dump whether or not the bug is present. diff --git a/gcc/testsuite/g++.dg/init/self1.C b/gcc/testsuite/g++.dg/init/self1.C index dd37c8e..7620833 100644 --- a/gcc/testsuite/g++.dg/init/self1.C +++ b/gcc/testsuite/g++.dg/init/self1.C @@ -10,7 +10,7 @@ void f(__SIZE_TYPE__) { int main() { - int* const savepos = sizeof(*savepos) ? 0 : 0; + int* const savepos = sizeof(*savepos) ? 0 : 0; /* { dg-error "invalid conversion" "convert" { target c++11 } } */ f (sizeof (*savepos)); diff --git a/gcc/testsuite/g++.dg/other/error22.C b/gcc/testsuite/g++.dg/other/error22.C index 225dcae..eba0746 100644 --- a/gcc/testsuite/g++.dg/other/error22.C +++ b/gcc/testsuite/g++.dg/other/error22.C @@ -5,5 +5,5 @@ extern "C" double fabs (double); void foo (double x) { - fabs (x) (); // { dg-error "__builtin_abs" } + fabs (x) (); // { dg-error "function" } } diff --git a/gcc/testsuite/g++.dg/other/error24.C b/gcc/testsuite/g++.dg/other/error24.C index 54343c5..e5e6a4f 100644 --- a/gcc/testsuite/g++.dg/other/error24.C +++ b/gcc/testsuite/g++.dg/other/error24.C @@ -8,6 +8,6 @@ void bar (int i, int j, double k) { foo (i && j) (); // { dg-error "\\(\\(?i != 0\\)? \\&\\& \\(?j != 0\\)?\\)" } - foo (!i || !j) (); // { dg-error "\\(\\(?i == 0\\)? \\|\\| \\(?j == 0\\)?\\)" } - foo (!i == !j) (); // { dg-error "\\(\\(?i != 0\\)? \\^ \\(?j == 0\\)?\\)" } + foo (!i || !j) (); // { dg-error "function" } + foo (!i == !j) (); // { dg-error "function" } } diff --git a/gcc/testsuite/g++.dg/other/error26.C b/gcc/testsuite/g++.dg/other/error26.C index fb2c8b7..ffe2728 100644 --- a/gcc/testsuite/g++.dg/other/error26.C +++ b/gcc/testsuite/g++.dg/other/error26.C @@ -2,5 +2,5 @@ void foo(__complex__ double x) { - __builtin_conj(x)(); // { dg-error "~x" } + __builtin_conj(x)(); // { dg-error "function" } } diff --git a/gcc/testsuite/g++.dg/parse/array-size2.C b/gcc/testsuite/g++.dg/parse/array-size2.C index 355ed61..3c83347 100644 --- a/gcc/testsuite/g++.dg/parse/array-size2.C +++ b/gcc/testsuite/g++.dg/parse/array-size2.C @@ -14,7 +14,7 @@ extern void bar (char *, char *); void foo (void) { - char g[(char *) &((struct S *) 0)->b - (char *) 0]; - char h[(__SIZE_TYPE__) &((struct S *) 8)->b]; + char g[(char *) &((struct S *) 0)->b - (char *) 0]; // { dg-error "constant" } + char h[(__SIZE_TYPE__) &((struct S *) 8)->b]; // { dg-error "constant" "" { xfail *-*-* } } bar (g, h); } diff --git a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C index 946f2e6..8014705 100644 --- a/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C +++ b/gcc/testsuite/g++.dg/ubsan/div-by-zero-1.C @@ -1,14 +1,10 @@ /* { dg-do compile } */ /* { dg-options "-fsanitize=integer-divide-by-zero" } */ -/* TODO: We expect an error on the invalid case here, because that - must be a constant-expression. This will be fixed when we have - proper delayed folding. */ - void foo (int i) { switch (i) case 0 * (1 / 0): /* { dg-warning "division by zero" } */ - ; /* { dg-error "division by zero" "" { xfail *-*-* } 10 } */ + ; /* { dg-error "is not a constant.expression" "" { target *-*-* } 8 } */ } diff --git a/gcc/testsuite/g++.dg/ubsan/shift-1.C b/gcc/testsuite/g++.dg/ubsan/shift-1.C index 05e049e..493a55c 100644 --- a/gcc/testsuite/g++.dg/ubsan/shift-1.C +++ b/gcc/testsuite/g++.dg/ubsan/shift-1.C @@ -8,10 +8,10 @@ foo (int x) /* None of the following should pass. */ switch (x) { - case 1 >> -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */ - case -1 >> -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */ - case 1 << -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */ - case -1 << -1: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */ + case 1 >> -1: /* { dg-error "operand of shift" "" } */ + case -1 >> -1: /* { dg-error "operand of shift" "" } */ + case 1 << -1: /* { dg-error "operand of shift" "" } */ + case -1 << -1: /* { dg-error "operand of shift" "" } */ return 1; } return 0; @@ -23,8 +23,8 @@ bar (int x) /* None of the following should pass. */ switch (x) { - case -1 >> 200: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */ - case 1 << 200: /* { dg-error "is not a constant expression" "" { xfail { *-*-* } } } */ + case -1 >> 200: /* { dg-error "operand of shift" "" } */ + case 1 << 200: /* { dg-error "operand of shift" "" } */ return 1; } return 0; diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C index 7cd76e7..a10e15b 100644 --- a/gcc/testsuite/g++.dg/warn/overflow-warn-1.C +++ b/gcc/testsuite/g++.dg/warn/overflow-warn-1.C @@ -17,7 +17,7 @@ enum e { /* But as in DR#031, the 1/0 in an evaluated subexpression means the whole expression violates the constraints. */ E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */ - /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */ + /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */ E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */ /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */ /* Again, overflow in evaluated subexpression. */ @@ -126,3 +126,11 @@ h2i (int x) ui = INT_MIN; ui = x ? INT_MIN : 1U; } +/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */ +/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 32 } */ +/* { dg-warning "invalid conversion from" "convert" { target *-*-* } 56 } */ +/* { dg-warning "invalid conversion from" "convert" { target c++11 } 58 } */ +/* { dg-error "is not a constant expression" "const" { target *-*-* } 65 } */ +/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 65 } */ +/* { dg-error "width not an integer constant" "bit.field" { target c++ } 32 } */ +/* { dg-error "is not a constant expression" "division" { target c++ } 32 } */ diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C index 73c0e00..c73a28c 100644 --- a/gcc/testsuite/g++.dg/warn/overflow-warn-3.C +++ b/gcc/testsuite/g++.dg/warn/overflow-warn-3.C @@ -17,7 +17,7 @@ enum e { /* But as in DR#031, the 1/0 in an evaluated subexpression means the whole expression violates the constraints. */ E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */ - /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */ + /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */ E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */ /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 21 } */ /* Again, overflow in evaluated subexpression. */ @@ -56,7 +56,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } /* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* } 55 } */ void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */ -/* { dg-warning "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 58 } */ +/* { dg-warning "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */ void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */ void @@ -65,7 +65,7 @@ g (int i) switch (i) { case 0 * (1/0): /* { dg-warning "division by zero" } */ - ; + ; /* { dg-error "is not a constant expression" "const" { target *-*-* } 67 } */ case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */ /* { dg-warning "overflow in constant expression" "constant" { target *-*-* } 69 } */ ; @@ -128,3 +128,9 @@ h2i (int x) ui = INT_MIN; ui = x ? INT_MIN : 1U; } +/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */ +/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 32 } */ +/* { dg-warning "invalid conversion from" "convert" { target c++11 } 60 } */ +/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 67 } */ +/* { dg-error "width not an integer constant" "bit.field" { target c++ } 32 } */ +/* { dg-error "is not a constant expression" "division" { target c++ } 32 } */ diff --git a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C index 24b3959..23a2585 100644 --- a/gcc/testsuite/g++.dg/warn/overflow-warn-4.C +++ b/gcc/testsuite/g++.dg/warn/overflow-warn-4.C @@ -17,7 +17,7 @@ enum e { /* But as in DR#031, the 1/0 in an evaluated subexpression means the whole expression violates the constraints. */ E4 = 0 * (1 / 0), /* { dg-warning "division by zero" } */ - /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { xfail *-*-* } 19 } */ + /* { dg-error "enumerator value for 'E4' is not an integer constant" "enum error" { target c++ } 19 } */ E5 = INT_MAX + 1, /* { dg-warning "integer overflow in expression" } */ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 21 } */ /* { dg-error "enumerator value for 'E5' is not an integer constant" "enum error" { target *-*-* } 21 } */ @@ -59,7 +59,7 @@ void *p = 0 * (INT_MAX + 1); /* { dg-warning "integer overflow in expression" } /* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 58 } */ void *q = 0 * (1 / 0); /* { dg-warning "division by zero" } */ -/* { dg-error "invalid conversion from 'int' to 'void*'" "null" { xfail *-*-* } 61 } */ +/* { dg-error "invalid conversion from 'int' to 'void" "null" { target *-*-* } 61 } */ void *r = (1 ? 0 : INT_MAX+1); /* { dg-bogus "integer overflow in expression" "" { xfail *-*-* } } */ void @@ -68,7 +68,7 @@ g (int i) switch (i) { case 0 * (1/0): /* { dg-warning "division by zero" } */ - ; + ; /* { dg-error "is not a constant expression" "const" { target *-*-* } 70 } */ case 1 + 0 * (INT_MAX + 1): /* { dg-warning "integer overflow in expression" } */ /* { dg-error "overflow in constant expression" "constant" { target *-*-* } 72 } */ ; @@ -131,3 +131,9 @@ h2i (int x) ui = INT_MIN; ui = x ? INT_MIN : 1U; } +/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 19 } */ +/* { dg-error "invalid conversion from" "convert" { target c++11 } 63 } */ +/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 34 } */ +/* { dg-error "division by zero is not a constant.expression" "division" { target c++11 } 70 } */ +/* { dg-error "width not an integer constant" "bit.field" { target c++ } 34 } */ +/* { dg-error "is not a constant expression" "division" { target c++ } 34 } */ diff --git a/gcc/testsuite/g++.old-deja/g++.other/null3.C b/gcc/testsuite/g++.old-deja/g++.other/null3.C index ff1d0669..96691d3 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/null3.C +++ b/gcc/testsuite/g++.old-deja/g++.other/null3.C @@ -3,5 +3,5 @@ void x() { int* p = 1==0; // { dg-warning "converting 'false' to pointer" "" { target { ! c++11 } } } -// { dg-error "cannot convert" "" { target c++11 } 5 } +// { dg-error "cannot convert" "" { target { c++11 } } 5 } } |