diff options
author | Martin Sebor <msebor@redhat.com> | 2016-06-08 19:03:17 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2016-06-08 21:03:17 +0200 |
commit | 44a845ca0e592ca187fbab07ac9e055b20fb11cc (patch) | |
tree | 3a15f43474585970a2b22a98bf6ff1b46fcf075f /gcc/cp/constexpr.c | |
parent | 379aea728edb345f42b19dfade5529f8f9e8a6da (diff) | |
download | gcc-44a845ca0e592ca187fbab07ac9e055b20fb11cc.zip gcc-44a845ca0e592ca187fbab07ac9e055b20fb11cc.tar.gz gcc-44a845ca0e592ca187fbab07ac9e055b20fb11cc.tar.bz2 |
re PR c++/70507 (integer overflow builtins not constant expressions)
PR c++/70507
PR c/68120
* builtins.def (BUILT_IN_ADD_OVERFLOW_P, BUILT_IN_SUB_OVERFLOW_P,
BUILT_IN_MUL_OVERFLOW_P): New builtins.
* builtins.c: Include gimple-fold.h.
(fold_builtin_arith_overflow): Handle
BUILT_IN_{ADD,SUB,MUL}_OVERFLOW_P.
(fold_builtin_3): Likewise.
* doc/extend.texi (Integer Overflow Builtins): Document
__builtin_{add,sub,mul}_overflow_p.
gcc/c/
* c-typeck.c (convert_arguments): Don't promote last argument
of BUILT_IN_{ADD,SUB,MUL}_OVERFLOW_P.
gcc/cp/
* constexpr.c: Include gimple-fold.h.
(cxx_eval_internal_function): New function.
(cxx_eval_call_expression): Call it.
(potential_constant_expression_1): Handle integer arithmetic
overflow built-ins.
* tree.c (builtin_valid_in_constant_expr_p): Handle
BUILT_IN_{ADD,SUB,MUL}_OVERFLOW_P.
gcc/c-family/
* c-common.c (check_builtin_function_arguments): Handle
BUILT_IN_{ADD,SUB,MUL}_OVERFLOW_P.
gcc/testsuite/
* c-c++-common/builtin-arith-overflow-1.c: Add test cases.
* c-c++-common/builtin-arith-overflow-2.c: New test.
* g++.dg/ext/builtin-arith-overflow-1.C: New test.
* g++.dg/cpp0x/constexpr-arith-overflow.C: New test.
* g++.dg/cpp1y/constexpr-arith-overflow.C: New test.
Co-Authored-By: Jakub Jelinek <jakub@redhat.com>
From-SVN: r237238
Diffstat (limited to 'gcc/cp/constexpr.c')
-rw-r--r-- | gcc/cp/constexpr.c | 107 |
1 files changed, 88 insertions, 19 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 482f8af..ba40435 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "builtins.h" #include "tree-inline.h" #include "ubsan.h" +#include "gimple-fold.h" static bool verify_constant (tree, bool, bool *, bool *); #define VERIFY_CONSTANT(X) \ @@ -1255,6 +1256,69 @@ cx_error_context (void) return r; } +/* Evaluate a call T to a GCC internal function when possible and return + the evaluated result or, under the control of CTX, give an error, set + NON_CONSTANT_P, and return the unevaluated call T otherwise. */ + +static tree +cxx_eval_internal_function (const constexpr_ctx *ctx, tree t, + bool lval, + bool *non_constant_p, bool *overflow_p) +{ + enum tree_code opcode = ERROR_MARK; + + switch (CALL_EXPR_IFN (t)) + { + case IFN_UBSAN_NULL: + case IFN_UBSAN_BOUNDS: + case IFN_UBSAN_VPTR: + return void_node; + + case IFN_ADD_OVERFLOW: + opcode = PLUS_EXPR; + break; + case IFN_SUB_OVERFLOW: + opcode = MINUS_EXPR; + break; + case IFN_MUL_OVERFLOW: + opcode = MULT_EXPR; + break; + + default: + if (!ctx->quiet) + error_at (EXPR_LOC_OR_LOC (t, input_location), + "call to internal function %qE", t); + *non_constant_p = true; + return t; + } + + /* Evaluate constant arguments using OPCODE and return a complex + number containing the result and the overflow bit. */ + tree arg0 = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 0), lval, + non_constant_p, overflow_p); + tree arg1 = cxx_eval_constant_expression (ctx, CALL_EXPR_ARG (t, 1), lval, + non_constant_p, overflow_p); + + if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST) + { + location_t loc = EXPR_LOC_OR_LOC (t, input_location); + tree type = TREE_TYPE (TREE_TYPE (t)); + tree result = fold_binary_loc (loc, opcode, type, + fold_convert_loc (loc, type, arg0), + fold_convert_loc (loc, type, arg1)); + tree ovf + = build_int_cst (type, arith_overflowed_p (opcode, type, arg0, arg1)); + /* Reset TREE_OVERFLOW to avoid warnings for the overflow. */ + if (TREE_OVERFLOW (result)) + TREE_OVERFLOW (result) = 0; + + return build_complex (TREE_TYPE (t), result, ovf); + } + + *non_constant_p = true; + return t; +} + /* Subroutine of cxx_eval_constant_expression. Evaluate the call expression tree T in the context of OLD_CALL expression evaluation. */ @@ -1270,18 +1334,8 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, bool depth_ok; if (fun == NULL_TREE) - switch (CALL_EXPR_IFN (t)) - { - case IFN_UBSAN_NULL: - case IFN_UBSAN_BOUNDS: - case IFN_UBSAN_VPTR: - return void_node; - default: - if (!ctx->quiet) - error_at (loc, "call to internal function"); - *non_constant_p = true; - return t; - } + return cxx_eval_internal_function (ctx, t, lval, + non_constant_p, overflow_p); if (TREE_CODE (fun) != FUNCTION_DECL) { @@ -4588,6 +4642,10 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, if (fun == NULL_TREE) { + /* Reset to allow the function to continue past the end + of the block below. Otherwise return early. */ + bool bail = true; + if (TREE_CODE (t) == CALL_EXPR && CALL_EXPR_FN (t) == NULL_TREE) switch (CALL_EXPR_IFN (t)) @@ -4598,16 +4656,27 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, case IFN_UBSAN_BOUNDS: case IFN_UBSAN_VPTR: return true; + + case IFN_ADD_OVERFLOW: + case IFN_SUB_OVERFLOW: + case IFN_MUL_OVERFLOW: + bail = false; + default: break; } - /* fold_call_expr can't do anything with IFN calls. */ - if (flags & tf_error) - error_at (EXPR_LOC_OR_LOC (t, input_location), - "call to internal function"); - return false; + + if (bail) + { + /* fold_call_expr can't do anything with IFN calls. */ + if (flags & tf_error) + error_at (EXPR_LOC_OR_LOC (t, input_location), + "call to internal function %qE", t); + return false; + } } - if (is_overloaded_fn (fun)) + + if (fun && is_overloaded_fn (fun)) { if (TREE_CODE (fun) == FUNCTION_DECL) { @@ -4652,7 +4721,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, i = num_artificial_parms_for (fun); fun = DECL_ORIGIN (fun); } - else + else if (fun) { if (RECUR (fun, rval)) /* Might end up being a constant function pointer. */; |