Merge C++ delayed folding branch.

* 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.

From-SVN: r230365
This commit is contained in:
Jason Merrill 2015-11-13 19:08:05 -05:00
parent 8fe17e23b0
commit cda0a029f4
46 changed files with 1164 additions and 317 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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"

View File

@ -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;

View File

@ -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

View File

@ -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"

View File

@ -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);

View File

@ -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

View File

@ -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
fold_sizeof_expr (tree t)
{
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 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);
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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. */

View File

@ -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);
}
}

View File

@ -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

View File

@ -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.

View File

@ -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"

View File

@ -47,3 +47,5 @@ right (int x)
r += -1U >> x;
return r;
}
/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */

View File

@ -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 } */

View File

@ -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 } */

View File

@ -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 } */

View File

@ -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* } } */

View File

@ -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;

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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" }
}

View File

@ -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" }
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 *-*-* } }

View File

@ -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" }

View File

@ -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.

View File

@ -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));

View File

@ -5,5 +5,5 @@ extern "C" double fabs (double);
void foo (double x)
{
fabs (x) (); // { dg-error "__builtin_abs" }
fabs (x) (); // { dg-error "function" }
}

View File

@ -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" }
}

View File

@ -2,5 +2,5 @@
void foo(__complex__ double x)
{
__builtin_conj(x)(); // { dg-error "~x" }
__builtin_conj(x)(); // { dg-error "function" }
}

View File

@ -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);
}

View File

@ -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 } */
}

View File

@ -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;

View File

@ -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 } */

View File

@ -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 } */

View File

@ -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 } */

View File

@ -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 }
}