+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.
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]
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. */
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);
}
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:
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:
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),
"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;
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)
;
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. */
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);
/* 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
}
}
- /* 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;
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
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. */
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);
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);
}
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)
{
offset to be from there. */
offset =
size_diffop (offset,
- convert (ssizetype,
+ fold_convert (ssizetype,
BINFO_OFFSET (virtual_offset)));
}
if (fixed_offset)
/* 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,
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);
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;
}
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))));
}
/* 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,
/* 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. */
= 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)));
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))),
= 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);
/* 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;
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"
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;
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,
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);
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] */
/* 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);
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;
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);
*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. */
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;
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
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
/* 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:
/* We can see these in statement-expressions. */
return true;
+ case EMPTY_CLASS_EXPR:
+ return false;
+
default:
if (objc_is_property_ref (t))
return false;
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
/* 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. */
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. */
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
|| 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)
{
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)))
&& 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"
/* 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);
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);
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);
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);
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.
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))
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);
/* 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
/* 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);
}
}
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);
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);
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)
{
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
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,
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
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
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)
{
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))
/* 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
"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);
}
}
{
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);
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);
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);
}
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;
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;
/* 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)
{
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))
{
{
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
/* 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
/* 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 */
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);
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);
}
maxindex = cp_convert (ptrdiff_type_node, maxindex, complain);
+ maxindex = fold_simple (maxindex);
+
if (TREE_CODE (atype) == ARRAY_TYPE)
{
ptype = build_pointer_type (type);
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. */
/* 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. */
/* 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
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;
"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
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;
}
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,
/* 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
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;
}
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))
if (init && EXPR_HAS_LOCATION (init))
elocus = EXPR_LOCATION (init);
+ cond = cp_fully_fold (cond);
switch (TREE_CODE (cond))
{
case GT_EXPR:
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)
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
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. */
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;
}
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;
}
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. */
code = TREE_CODE (type);
- /* FIXME remove for delayed folding. */
- exp = scalar_constant_value (exp);
if (error_operand_p (exp))
return error_mark_node;
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
{
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
|= (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);
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);
}
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
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
{
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
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;
}
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)
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);
}
}
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;
}
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.
result = build2 (EXACT_DIV_EXPR, restype, op0,
cp_convert (restype, op1, complain));
- return fold_if_not_in_template (result);
+ return result;
}
\f
/* Construct and perhaps optimize a tree representation
/* 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;
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:
{
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)
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)))
{
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)))
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)
}
}
- 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
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);
}
}
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;
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. */
}
}
+ 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;
}
}
{
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)
}
}
- return cxx_dialect == cxx98 || ok;
+ return ok;
}
/* Process the initializer INIT for a variable of type TYPE, emitting
+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.
# 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"
r += -1U >> x;
return r;
}
+
+/* { dg-error "left operand of shift expression" "shift" { target c++ } 9 } */
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 } */
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 } */
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 } */
-/* { dg-do compile } */
+/* { dg-do compile { target { c } } } */
/* { dg-options "-fdump-tree-original" } */
/* { dg-additional-options "-fno-common" { target hppa*-*-hpux* } } */
{
/* I am surprised this is considered a constexpr */
return *((Inner *)4);
- } // { dg-error "reinterpret_cast" "" { xfail *-*-* } }
+ } // { dg-error "reinterpret_cast" "" }
};
B B::instance;
--- /dev/null
+// 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;
+}
--- /dev/null
+// { 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");
+}
--- /dev/null
+// { 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" }
+}
+
--- /dev/null
+// { 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" }
+}
+
--- /dev/null
+/* { 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;
+}
+
--- /dev/null
+/* { 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;
+}
+
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; };
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 *-*-* } }
// PR c++/27601
// Origin: Patrik Hägglund <patrik.hagglund@bredband.net>
// { dg-do compile }
+// { dg-options "-Wno-pointer-arith" }
struct bar {
static int foo;
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" }
// { 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.
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));
void foo (double x)
{
- fabs (x) (); // { dg-error "__builtin_abs" }
+ fabs (x) (); // { dg-error "function" }
}
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" }
}
void foo(__complex__ double x)
{
- __builtin_conj(x)(); // { dg-error "~x" }
+ __builtin_conj(x)(); // { dg-error "function" }
}
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);
}
/* { 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 } */
}
/* 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;
/* 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;
/* 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. */
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 } */
/* 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. */
/* { 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
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 } */
;
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 } */
/* 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 } */
/* { 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
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 } */
;
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 } */
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 }
}