From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 91937 invoked by alias); 6 Jun 2016 12:36:31 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 91926 invoked by uid 89); 6 Jun 2016 12:36:30 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.3 required=5.0 tests=BAYES_00,KAM_LAZY_DOMAIN_SECURITY,RP_MATCHES_RCVD,SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=15000000000, sk:lookup_, fnd, lll X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Mon, 06 Jun 2016 12:36:24 +0000 Received: from int-mx10.intmail.prod.int.phx2.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0D3A2C04D2A9; Mon, 6 Jun 2016 12:36:23 +0000 (UTC) Received: from tucnak.zalov.cz (ovpn-116-51.ams2.redhat.com [10.36.116.51]) by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id u56CaK8A021239 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Mon, 6 Jun 2016 08:36:21 -0400 Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id u56CaIUh010310; Mon, 6 Jun 2016 14:36:19 +0200 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id u56CaHR3010309; Mon, 6 Jun 2016 14:36:17 +0200 Date: Mon, 06 Jun 2016 12:36:00 -0000 From: Jakub Jelinek To: Martin Sebor Cc: Gcc Patch List , Jason Merrill , "Joseph S. Myers" Subject: Re: [PATCH] integer overflow checking builtins in constant expressions Message-ID: <20160606123617.GW7387@tucnak.redhat.com> Reply-To: Jakub Jelinek References: <20160601075212.GL28550@tucnak.redhat.com> <574EFC8F.2040400@gmail.com> <574FA3BC.8090603@gmail.com> <20160602072316.GY28550@tucnak.redhat.com> <5750BF82.5030203@gmail.com> <5750CF25.1080801@gmail.com> <20160603070637.GA7387@tucnak.redhat.com> <5751A26C.1060201@gmail.com> <20160603153235.GK7387@tucnak.redhat.com> <5751E408.1010707@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <5751E408.1010707@gmail.com> User-Agent: Mutt/1.5.24 (2015-08-30) X-IsSubscribed: yes X-SW-Source: 2016-06/txt/msg00376.txt.bz2 On Fri, Jun 03, 2016 at 02:09:44PM -0600, Martin Sebor wrote: > I see. I've made the change in the latest update to the patch > but I wasn't able to create a test case to verify it. Maybe > that's because this is constexpr the COMPLEX_EXPR doesn't make > it far enough to trigger a problem. If there is a way to test > it I'd appreciate a suggestion for how (otherwise, if not caught > in a code review like in this case, it would be a ticking time > bomb). As you haven't been willing to try the __builtin_*_overflow_p way, I've done that myself, it hasn't been really that hard. I've also found another bug, when computing the value that is stored in the constexpr function, you weren't converting the INTEGER_CST args to type, so you could get incorrect type of the result or other issues. > It also occurred to me that a more robust solution might be to > change build_complex to either enforce as a precondition that > the members have a type that matches the complex type. I've > taken the liberty of making this change as part of this patch. IMHO it doesn't belong to this patch, feel free to submit the tree.c change separately. > (It seems that an even better solution would be to have > build_complex convert the arguments to the expected type > so that callers don't have to worry about it.) I diagree with that, build_complex is a low-level function, it shouldn't perform such conversions. 2016-06-06 Martin Sebor Jakub Jelinek 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): Likewise. 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/cpp0x/constexpr-arith-overflow.C: New test. * g++.dg/cpp1y/constexpr-arith-overflow.C: New test. --- gcc/builtins.c.jj 2016-06-03 21:25:16.595678286 +0200 +++ gcc/builtins.c 2016-06-06 11:48:06.800100603 +0200 @@ -64,6 +64,7 @@ along with GCC; see the file COPYING3. #include "rtl-chkp.h" #include "internal-fn.h" #include "case-cfn-macros.h" +#include "gimple-fold.h" struct target_builtins default_target_builtins; @@ -7943,18 +7944,28 @@ fold_builtin_unordered_cmp (location_t l /* Fold __builtin_{,s,u}{add,sub,mul}{,l,ll}_overflow, either into normal arithmetics if it can never overflow, or into internal functions that return both result of arithmetics and overflowed boolean flag in - a complex integer result, or some other check for overflow. */ + a complex integer result, or some other check for overflow. + Similarly fold __builtin_{add,sub,mul}_overflow_p to just the overflow + checking part of that. */ static tree fold_builtin_arith_overflow (location_t loc, enum built_in_function fcode, tree arg0, tree arg1, tree arg2) { enum internal_fn ifn = IFN_LAST; - tree type = TREE_TYPE (TREE_TYPE (arg2)); - tree mem_arg2 = build_fold_indirect_ref_loc (loc, arg2); + /* The code of the expression corresponding to the type-generic + built-in, or ERROR_MARK for the type-specific ones. */ + enum tree_code opcode = ERROR_MARK; + bool ovf_only = false; + switch (fcode) { + case BUILT_IN_ADD_OVERFLOW_P: + ovf_only = true; + /* FALLTHRU */ case BUILT_IN_ADD_OVERFLOW: + opcode = PLUS_EXPR; + /* FALLTHRU */ case BUILT_IN_SADD_OVERFLOW: case BUILT_IN_SADDL_OVERFLOW: case BUILT_IN_SADDLL_OVERFLOW: @@ -7963,7 +7974,12 @@ fold_builtin_arith_overflow (location_t case BUILT_IN_UADDLL_OVERFLOW: ifn = IFN_ADD_OVERFLOW; break; + case BUILT_IN_SUB_OVERFLOW_P: + ovf_only = true; + /* FALLTHRU */ case BUILT_IN_SUB_OVERFLOW: + opcode = MINUS_EXPR; + /* FALLTHRU */ case BUILT_IN_SSUB_OVERFLOW: case BUILT_IN_SSUBL_OVERFLOW: case BUILT_IN_SSUBLL_OVERFLOW: @@ -7972,7 +7988,12 @@ fold_builtin_arith_overflow (location_t case BUILT_IN_USUBLL_OVERFLOW: ifn = IFN_SUB_OVERFLOW; break; + case BUILT_IN_MUL_OVERFLOW_P: + ovf_only = true; + /* FALLTHRU */ case BUILT_IN_MUL_OVERFLOW: + opcode = MULT_EXPR; + /* FALLTHRU */ case BUILT_IN_SMUL_OVERFLOW: case BUILT_IN_SMULL_OVERFLOW: case BUILT_IN_SMULLL_OVERFLOW: @@ -7984,6 +8005,25 @@ fold_builtin_arith_overflow (location_t default: gcc_unreachable (); } + + /* For the "generic" overloads, the first two arguments can have different + types and the last argument determines the target type to use to check + for overflow. The arguments of the other overloads all have the same + type. */ + tree type = ovf_only ? TREE_TYPE (arg2) : TREE_TYPE (TREE_TYPE (arg2)); + + /* For the __builtin_{add,sub,mul}_overflow_p builtins, when the first two + arguments are constant, attempt to fold the built-in call into a constant + expression indicating whether or not it detected an overflow. */ + if (ovf_only + && TREE_CODE (arg0) == INTEGER_CST + && TREE_CODE (arg1) == INTEGER_CST) + /* Perform the computation in the target type and check for overflow. */ + return omit_one_operand_loc (loc, boolean_type_node, + arith_overflowed_p (opcode, type, arg0, arg1) + ? boolean_true_node : boolean_false_node, + arg2); + tree ctype = build_complex_type (type); tree call = build_call_expr_internal_loc (loc, ifn, ctype, 2, arg0, arg1); @@ -7991,6 +8031,11 @@ fold_builtin_arith_overflow (location_t tree intres = build1_loc (loc, REALPART_EXPR, type, tgt); tree ovfres = build1_loc (loc, IMAGPART_EXPR, type, tgt); ovfres = fold_convert_loc (loc, boolean_type_node, ovfres); + + if (ovf_only) + return omit_one_operand_loc (loc, boolean_type_node, ovfres, arg2); + + tree mem_arg2 = build_fold_indirect_ref_loc (loc, arg2); tree store = fold_build2_loc (loc, MODIFY_EXPR, void_type_node, mem_arg2, intres); return build2_loc (loc, COMPOUND_EXPR, boolean_type_node, store, ovfres); @@ -8340,6 +8385,9 @@ fold_builtin_3 (location_t loc, tree fnd case BUILT_IN_ADD_OVERFLOW: case BUILT_IN_SUB_OVERFLOW: case BUILT_IN_MUL_OVERFLOW: + case BUILT_IN_ADD_OVERFLOW_P: + case BUILT_IN_SUB_OVERFLOW_P: + case BUILT_IN_MUL_OVERFLOW_P: case BUILT_IN_SADD_OVERFLOW: case BUILT_IN_SADDL_OVERFLOW: case BUILT_IN_SADDLL_OVERFLOW: --- gcc/cp/constexpr.c.jj 2016-05-24 10:56:00.972164643 +0200 +++ gcc/cp/constexpr.c 2016-06-06 12:07:45.551788040 +0200 @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. #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 constexp 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, 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, 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, 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. */; --- gcc/cp/tree.c.jj 2016-05-13 22:23:03.024721307 +0200 +++ gcc/cp/tree.c 2016-06-06 11:54:23.675203508 +0200 @@ -352,6 +352,35 @@ builtin_valid_in_constant_expr_p (const_ case BUILT_IN_FUNCTION: case BUILT_IN_LINE: + /* The following built-ins are valid in constant expressions + when their arguments are. */ + case BUILT_IN_ADD_OVERFLOW: + case BUILT_IN_ADD_OVERFLOW_P: + case BUILT_IN_SADD_OVERFLOW: + case BUILT_IN_SADDL_OVERFLOW: + case BUILT_IN_SADDLL_OVERFLOW: + case BUILT_IN_UADD_OVERFLOW: + case BUILT_IN_UADDL_OVERFLOW: + case BUILT_IN_UADDLL_OVERFLOW: + + case BUILT_IN_SUB_OVERFLOW: + case BUILT_IN_SUB_OVERFLOW_P: + case BUILT_IN_SSUB_OVERFLOW: + case BUILT_IN_SSUBL_OVERFLOW: + case BUILT_IN_SSUBLL_OVERFLOW: + case BUILT_IN_USUB_OVERFLOW: + case BUILT_IN_USUBL_OVERFLOW: + case BUILT_IN_USUBLL_OVERFLOW: + + case BUILT_IN_MUL_OVERFLOW: + case BUILT_IN_MUL_OVERFLOW_P: + case BUILT_IN_SMUL_OVERFLOW: + case BUILT_IN_SMULL_OVERFLOW: + case BUILT_IN_SMULLL_OVERFLOW: + case BUILT_IN_UMUL_OVERFLOW: + case BUILT_IN_UMULL_OVERFLOW: + case BUILT_IN_UMULLL_OVERFLOW: + /* These have constant results even if their operands are non-constant. */ case BUILT_IN_CONSTANT_P: --- gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c.jj 2014-11-12 13:28:47.188688801 +0100 +++ gcc/testsuite/c-c++-common/builtin-arith-overflow-1.c 2016-06-06 12:47:18.567054514 +0200 @@ -6,6 +6,9 @@ f1 (void) int x = __builtin_add_overflow (); /* { dg-error "not enough arguments to function" } */ x += __builtin_sub_overflow (); /* { dg-error "not enough arguments to function" } */ x += __builtin_mul_overflow (); /* { dg-error "not enough arguments to function" } */ + x += __builtin_add_overflow_p (); /* { dg-error "not enough arguments to function" } */ + x += __builtin_sub_overflow_p (); /* { dg-error "not enough arguments to function" } */ + x += __builtin_mul_overflow_p (); /* { dg-error "not enough arguments to function" } */ return x; } @@ -15,6 +18,10 @@ f2 (int a, int b, int *c, int d) int x = __builtin_add_overflow (a, b, c, d); /* { dg-error "too many arguments to function" } */ x += __builtin_sub_overflow (a, b, c, d, d, d); /* { dg-error "too many arguments to function" } */ x += __builtin_mul_overflow (a, b, c, d); /* { dg-error "too many arguments to function" } */ + x += __builtin_add_overflow_p (a, b, d, d); /* { dg-error "too many arguments to function" } */ + x += __builtin_sub_overflow_p (a, b, d, d, 1, d); /* { dg-error "too many arguments to function" } */ + x += __builtin_mul_overflow_p (a, b, d, d); /* { dg-error "too many arguments to function" } */ + return x; } @@ -33,6 +40,15 @@ f3 (float fa, int a, _Complex long int c x += __builtin_add_overflow (a, pb, c); /* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */ x += __builtin_sub_overflow (a, eb, c); x += __builtin_mul_overflow (a, bb, c); + x += __builtin_add_overflow_p (fa, b, a); /* { dg-error "argument 1 in call to function\[^\n\r]*does not have integral type" } */ + x += __builtin_sub_overflow_p (ca, b, eb); /* { dg-error "argument 1 in call to function\[^\n\r]*does not have integral type" } */ + x += __builtin_mul_overflow_p (a, fb, bb); /* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */ + x += __builtin_add_overflow_p (a, pb, a); /* { dg-error "argument 2 in call to function\[^\n\r]*does not have integral type" } */ + x += __builtin_sub_overflow_p (a, eb, eb); + x += __builtin_mul_overflow_p (a, bb, bb); + x += __builtin_add_overflow_p (a, b, fa); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have integral type" } */ + x += __builtin_sub_overflow_p (a, b, ca); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have integral type" } */ + x += __builtin_mul_overflow_p (a, b, c); /* { dg-error "argument 3 in call to function\[^\n\r]*does not have integral type" } */ return x; } --- gcc/testsuite/c-c++-common/builtin-arith-overflow-2.c.jj 2016-06-06 11:37:40.770240477 +0200 +++ gcc/testsuite/c-c++-common/builtin-arith-overflow-2.c 2016-06-06 12:52:32.419977756 +0200 @@ -0,0 +1,493 @@ +/* PR c/68120 - can't easily deal with integer overflow at compile time */ +/* { dg-do run } */ +/* { dg-additional-options "-Wno-long-long" } */ + +#define SCHAR_MAX __SCHAR_MAX__ +#define SHRT_MAX __SHRT_MAX__ +#define INT_MAX __INT_MAX__ +#define LONG_MAX __LONG_MAX__ +#define LLONG_MAX __LONG_LONG_MAX__ + +#define SCHAR_MIN (-__SCHAR_MAX__ - 1) +#define SHRT_MIN (-__SHRT_MAX__ - 1) +#define INT_MIN (-__INT_MAX__ - 1) +#define LONG_MIN (-__LONG_MAX__ - 1) +#define LLONG_MIN (-__LONG_LONG_MAX__ - 1) + +#define UCHAR_MAX (SCHAR_MAX * 2U + 1) +#define USHRT_MAX (SHRT_MAX * 2U + 1) +#define UINT_MAX (INT_MAX * 2U + 1) +#define ULONG_MAX (LONG_MAX * 2LU + 1) +#define ULLONG_MAX (LLONG_MAX * 2LLU + 1) + +#define USCHAR_MIN (-__USCHAR_MAX__ - 1) +#define USHRT_MIN (-__USHRT_MAX__ - 1) +#define UINT_MIN (-__UINT_MAX__ - 1) +#define ULONG_MIN (-__ULONG_MAX__ - 1) +#define ULLONG_MIN (-__ULONG_LONG_MAX__ - 1) + +/* Number of failed runtime assertions. */ +int nfails; + +void __attribute__ ((noclone, noinline)) +runtime_assert (int expr, int line) +{ + if (!expr) + { + __builtin_printf ("line %i: assertion failed\n", line); + ++nfails; + } +} + +/* Helper macros for run-time testing. */ +#define add(x, y) ((x) + (y)) +#define sadd(x, y) ((x) + (y)) +#define saddl(x, y) ((x) + (y)) +#define saddll(x, y) ((x) + (y)) +#define uadd(x, y) ((x) + (y)) +#define uaddl(x, y) ((x) + (y)) +#define uaddll(x, y) ((x) + (y)) +#define sub(x, y) ((x) - (y)) +#define ssub(x, y) ((x) - (y)) +#define ssubl(x, y) ((x) - (y)) +#define ssubll(x, y) ((x) - (y)) +#define usub(x, y) ((x) - (y)) +#define usubl(x, y) ((x) - (y)) +#define usubll(x, y) ((x) - (y)) +#define mul(x, y) ((x) * (y)) +#define smul(x, y) ((x) * (y)) +#define smull(x, y) ((x) * (y)) +#define smulll(x, y) ((x) * (y)) +#define umul(x, y) ((x) * (y)) +#define umull(x, y) ((x) * (y)) +#define umulll(x, y) ((x) * (y)) + +int main (void) +{ + +#if __cplusplus >= 201103L +# define StaticAssert(expr) static_assert ((expr), #expr) +#elif __STDC_VERSION__ >= 201112L +# define StaticAssert(expr) _Static_assert ((expr), #expr) +#else + /* The following pragma has no effect due to bug 70888 - #pragma + diagnostic ignored -Wlong-long ineffective with __LONG_LONG_MAX__ + in c++98 mode. */ +# pragma GCC diagnostic ignored "-Wlong-long" +# pragma GCC diagnostic ignored "-Wunused-local-typedefs" + +# define CONCAT(a, b) a ## b +# define CAT(a, b) CONCAT (a, b) +# define StaticAssert(expr) \ + typedef int CAT (StaticAssert_, __LINE__) [1 - 2 * !(expr)] +#endif + + /* Make extra effort to prevent constant folding seeing the constant + values of the arguments and optimizing the run-time test into + a constant. */ +#define RuntimeAssert(op, T, U, x, y, vflow) \ + do { \ + volatile T a = (x), b = (y); \ + U c = 0; \ + volatile int vf = __builtin_ ## op ## _overflow (a, b, &c); \ + runtime_assert ((vf == vflow), __LINE__); \ + if (vf == 0) \ + runtime_assert (op (a, b) == c, __LINE__); \ + } while (0) + + /* Verify that each call to the type-generic __builtin_op_overflow(x, y) + yields a constant expression equal to z indicating whether or not + the constant expression (x op y) overflows when evaluated in type T. */ +# define G_TEST(op, T, x, y, vflow) \ + RuntimeAssert(op, __typeof__ (op (x, y)), T, x, y, vflow); \ + StaticAssert ((vflow) == __builtin_ ## op ## _overflow_p ((x), (y), (T)0)) + + /* Addition. */ + G_TEST (add, signed char, 0, 0, 0); + G_TEST (add, signed char, 0, SCHAR_MAX, 0); + G_TEST (add, signed char, 1, SCHAR_MAX, 1); + G_TEST (add, signed char, SCHAR_MAX, SCHAR_MAX, 1); + G_TEST (add, signed char, 0, SCHAR_MIN, 0); + G_TEST (add, signed char, -1, SCHAR_MIN, 1); + /* Verify any slicing in the result type doesn't prevent the overflow + from being detected. */ + G_TEST (add, signed char, UCHAR_MAX + 1, 0, 1); + G_TEST (add, signed char, UCHAR_MAX + 1, 1, 1); + G_TEST (add, signed char, 1, UCHAR_MAX + 1, 1); + + G_TEST (add, unsigned char, 0, 0, 0); + /* Verify any slicing in the result type doesn't prevent the overflow + from being detected. */ + G_TEST (add, unsigned char, UCHAR_MAX + 1, 0, 1); + G_TEST (add, unsigned char, UCHAR_MAX + 1, 1, 1); + G_TEST (add, unsigned char, 1, UCHAR_MAX + 1, 1); + + G_TEST (add, short, 0, 0, 0); + G_TEST (add, short, 0, SHRT_MAX, 0); + G_TEST (add, short, 1, SHRT_MAX, 1); + G_TEST (add, short, SHRT_MAX, SHRT_MAX, 1); + G_TEST (add, short, 0, SHRT_MIN, 0); + G_TEST (add, short, -1, SHRT_MIN, 1); + G_TEST (add, short, SHRT_MIN, SHRT_MIN, 1); + + G_TEST (add, int, 0, 0, 0); + G_TEST (add, int, 0, INT_MAX, 0); + G_TEST (add, int, 1, INT_MAX, 1); + G_TEST (add, int, INT_MAX, INT_MAX, 1); + G_TEST (add, int, 0, INT_MIN, 0); + G_TEST (add, int, -1, INT_MIN, 1); + G_TEST (add, int, INT_MIN, INT_MIN, 1); + + G_TEST (add, long, 0, 0, 0); + G_TEST (add, long, 0, LONG_MAX, 0); + G_TEST (add, long, 1, LONG_MAX, 1); + G_TEST (add, long, LONG_MAX, LONG_MAX, 1); + G_TEST (add, long, 0, LONG_MIN, 0); + G_TEST (add, long, -1, LONG_MIN, 1); + G_TEST (add, long, LONG_MIN, LONG_MIN, 1); + + G_TEST (add, long long, 0, 0, 0); + G_TEST (add, long long, 0, LLONG_MAX, 0); + G_TEST (add, long long, 1, LLONG_MAX, 1); + G_TEST (add, long long, LLONG_MAX, LLONG_MAX, 1); + G_TEST (add, long long, 0, LLONG_MIN, 0); + G_TEST (add, long long, -1, LLONG_MIN, 1); + G_TEST (add, long long, LLONG_MIN, LLONG_MIN, 1); + + /* Subtraction */ + G_TEST (sub, unsigned char, 0, 0, 0); + G_TEST (sub, unsigned char, 0, UCHAR_MAX, 1); + G_TEST (sub, unsigned char, 1, UCHAR_MAX, 1); + + G_TEST (sub, unsigned char, UCHAR_MAX, UCHAR_MAX, 0); + G_TEST (sub, unsigned short, 0, 0, 0); + G_TEST (sub, unsigned short, 0, USHRT_MAX, 1); + G_TEST (sub, unsigned short, 1, USHRT_MAX, 1); + G_TEST (sub, unsigned short, USHRT_MAX, USHRT_MAX, 0); + + G_TEST (sub, unsigned, 0, 0, 0); + G_TEST (sub, unsigned, 0, UINT_MAX, 1); + G_TEST (sub, unsigned, 1, UINT_MAX, 1); + G_TEST (sub, unsigned, UINT_MAX, UINT_MAX, 0); + + G_TEST (sub, unsigned long, 0, 0, 0); + G_TEST (sub, unsigned long, 0, ULONG_MAX, 1); + G_TEST (sub, unsigned long, 1, ULONG_MAX, 1); + G_TEST (sub, unsigned long, ULONG_MAX, ULONG_MAX, 0); + + G_TEST (sub, unsigned long long, 0, 0, 0); + G_TEST (sub, unsigned long long, 0, ULLONG_MAX, 1); + G_TEST (sub, unsigned long long, 1, ULLONG_MAX, 1); + G_TEST (sub, unsigned long long, ULLONG_MAX, ULLONG_MAX, 0); + + G_TEST (sub, signed char, 0, 0, 0); + G_TEST (sub, signed char, 0, SCHAR_MAX, 0); + G_TEST (sub, signed char, 1, SCHAR_MAX, 0); + G_TEST (sub, signed char, SCHAR_MAX, SCHAR_MAX, 0); + G_TEST (sub, signed char, SCHAR_MIN, 1, 1); + G_TEST (sub, signed char, 0, SCHAR_MIN, 1); + G_TEST (sub, signed char, -1, SCHAR_MIN, 0); + + G_TEST (sub, short, 0, 0, 0); + G_TEST (sub, short, 0, SHRT_MAX, 0); + G_TEST (sub, short, 1, SHRT_MAX, 0); + G_TEST (sub, short, SHRT_MAX, SHRT_MAX, 0); + G_TEST (sub, short, 0, SHRT_MIN, 1); + G_TEST (sub, short, -1, SHRT_MIN, 0); + G_TEST (sub, short, SHRT_MIN, SHRT_MIN, 0); + + G_TEST (sub, int, 0, 0, 0); + G_TEST (sub, int, 0, INT_MAX, 0); + G_TEST (sub, int, 1, INT_MAX, 0); + G_TEST (sub, int, INT_MAX, INT_MAX, 0); + G_TEST (sub, int, 0, INT_MIN, 1); + G_TEST (sub, int, -1, INT_MIN, 0); + G_TEST (sub, int, INT_MIN, INT_MIN, 0); + + G_TEST (sub, long, 0, 0, 0); + G_TEST (sub, long, 0, LONG_MAX, 0); + G_TEST (sub, long, 1, LONG_MAX, 0); + G_TEST (sub, long, LONG_MAX, LONG_MAX, 0); + G_TEST (sub, long, 0, LONG_MIN, 1); + G_TEST (sub, long, -1, LONG_MIN, 0); + G_TEST (sub, long, LONG_MIN, LONG_MIN, 0); + + G_TEST (sub, long long, 0, 0, 0); + G_TEST (sub, long long, 0, LLONG_MAX, 0); + G_TEST (sub, long long, 1, LLONG_MAX, 0); + G_TEST (sub, long long, LLONG_MAX, LLONG_MAX, 0); + G_TEST (sub, long long, 0, LLONG_MIN, 1); + G_TEST (sub, long long, -1, LLONG_MIN, 0); + G_TEST (sub, long long, LLONG_MIN, LLONG_MIN, 0); + + G_TEST (sub, unsigned char, 0, 0, 0); + G_TEST (sub, unsigned char, 0, UCHAR_MAX, 1); + G_TEST (sub, unsigned char, 1, UCHAR_MAX, 1); + G_TEST (sub, unsigned char, UCHAR_MAX, UCHAR_MAX, 0); + + G_TEST (sub, unsigned short, 0, 0, 0); + G_TEST (sub, unsigned short, 0, USHRT_MAX, 1); + G_TEST (sub, unsigned short, 1, USHRT_MAX, 1); + G_TEST (sub, unsigned short, USHRT_MAX, USHRT_MAX, 0); + + G_TEST (sub, unsigned, 0, 0, 0); + G_TEST (sub, unsigned, 0, UINT_MAX, 1); + G_TEST (sub, unsigned, 1, UINT_MAX, 1); + G_TEST (sub, unsigned, UINT_MAX, UINT_MAX, 0); + + G_TEST (sub, unsigned long, 0, 0, 0); + G_TEST (sub, unsigned long, 0, ULONG_MAX, 1); + G_TEST (sub, unsigned long, 1, ULONG_MAX, 1); + G_TEST (sub, unsigned long, ULONG_MAX, ULONG_MAX, 0); + + G_TEST (sub, unsigned long long, 0, 0, 0); + G_TEST (sub, unsigned long long, 0, ULLONG_MAX, 1); + G_TEST (sub, unsigned long long, 1, ULLONG_MAX, 1); + G_TEST (sub, unsigned long long, ULLONG_MAX, ULLONG_MAX, 0); + + /* Multiplication. */ + G_TEST (mul, unsigned char, 0, 0, 0); + G_TEST (mul, unsigned char, 0, UCHAR_MAX, 0); + G_TEST (mul, unsigned char, 1, UCHAR_MAX, 0); + G_TEST (mul, unsigned char, 2, UCHAR_MAX, 1); + G_TEST (mul, unsigned char, UCHAR_MAX, UCHAR_MAX, 1); + + G_TEST (mul, unsigned short, 0, 0, 0); + G_TEST (mul, unsigned short, 0, USHRT_MAX, 0); + G_TEST (mul, unsigned short, 1, USHRT_MAX, 0); + G_TEST (mul, unsigned short, USHRT_MAX, 2, 1); + G_TEST (mul, unsigned short, USHRT_MAX, USHRT_MAX, 1); + + G_TEST (mul, unsigned, 0, 0, 0); + G_TEST (mul, unsigned, 0, UINT_MAX, 0); + G_TEST (mul, unsigned, 1, UINT_MAX, 0); + G_TEST (mul, unsigned, 2, UINT_MAX, 1); + G_TEST (mul, unsigned, UINT_MAX, UINT_MAX, 1); + + G_TEST (mul, unsigned long, 0, 0, 0); + G_TEST (mul, unsigned long, 0, ULONG_MAX, 0); + G_TEST (mul, unsigned long, 1, ULONG_MAX, 0); + G_TEST (mul, unsigned long, 2, ULONG_MAX, 1); + G_TEST (mul, unsigned long, ULONG_MAX, ULONG_MAX, 1); + + G_TEST (mul, unsigned long long, 0, 0, 0); + G_TEST (mul, unsigned long long, 0, ULLONG_MAX, 0); + G_TEST (mul, unsigned long long, 1, ULLONG_MAX, 0); + G_TEST (mul, unsigned long long, 2, ULLONG_MAX, 1); + G_TEST (mul, unsigned long long, ULLONG_MAX, ULLONG_MAX, 1); + + G_TEST (mul, signed char, 0, 0, 0); + G_TEST (mul, signed char, 0, SCHAR_MAX, 0); + G_TEST (mul, signed char, 1, SCHAR_MAX, 0); + G_TEST (mul, signed char, SCHAR_MAX, SCHAR_MAX, 1); + G_TEST (mul, signed char, SCHAR_MIN, 1, 0); + G_TEST (mul, signed char, 0, SCHAR_MIN, 0); + G_TEST (mul, signed char, -1, SCHAR_MIN, 1); + + G_TEST (mul, short, 0, 0, 0); + G_TEST (mul, short, 0, SHRT_MAX, 0); + G_TEST (mul, short, 1, SHRT_MAX, 0); + G_TEST (mul, short, SHRT_MAX, SHRT_MAX, 1); + G_TEST (mul, short, 0, SHRT_MIN, 0); + G_TEST (mul, short, -1, SHRT_MIN, 1); + G_TEST (mul, short, SHRT_MIN, SHRT_MIN, 1); + + G_TEST (mul, int, 0, 0, 0); + G_TEST (mul, int, 0, INT_MAX, 0); + G_TEST (mul, int, 1, INT_MAX, 0); + G_TEST (mul, int, INT_MAX, INT_MAX, 1); + G_TEST (mul, int, 0, INT_MIN, 0); + G_TEST (mul, int, -1, INT_MIN, 1); + G_TEST (mul, int, INT_MIN, INT_MIN, 1); + + G_TEST (mul, long, 0, 0, 0); + G_TEST (mul, long, 0, LONG_MAX, 0); + G_TEST (mul, long, 1, LONG_MAX, 0); + G_TEST (mul, long, LONG_MAX, LONG_MAX, 1); + G_TEST (mul, long, 0, LONG_MIN, 0); + G_TEST (mul, long, -1, LONG_MIN, 1); + G_TEST (mul, long, LONG_MIN, LONG_MIN, 1); + + G_TEST (mul, long long, 0, 0, 0); + G_TEST (mul, long long, 0, LLONG_MAX, 0); + G_TEST (mul, long long, 1, LLONG_MAX, 0); + G_TEST (mul, long long, LLONG_MAX, LLONG_MAX, 1); + G_TEST (mul, long long, 0, LLONG_MIN, 0); + G_TEST (mul, long long, -1, LLONG_MIN, 1); + G_TEST (mul, long long, LLONG_MIN, LLONG_MIN, 1); + + G_TEST (mul, unsigned char, 0, 0, 0); + G_TEST (mul, unsigned char, 0, UCHAR_MAX, 0); + G_TEST (mul, unsigned char, 1, UCHAR_MAX, 0); + G_TEST (mul, unsigned char, UCHAR_MAX, UCHAR_MAX, 1); + + G_TEST (mul, unsigned short, 0, 0, 0); + G_TEST (mul, unsigned short, 0, USHRT_MAX, 0); + G_TEST (mul, unsigned short, 1, USHRT_MAX, 0); + G_TEST (mul, unsigned short, USHRT_MAX, USHRT_MAX, 1); + + G_TEST (mul, unsigned, 0, 0, 0); + G_TEST (mul, unsigned, 0, UINT_MAX, 0); + G_TEST (mul, unsigned, 1, UINT_MAX, 0); + G_TEST (mul, unsigned, UINT_MAX, UINT_MAX, 1); + + G_TEST (mul, unsigned long, 0, 0, 0); + G_TEST (mul, unsigned long, 0, ULONG_MAX, 0); + G_TEST (mul, unsigned long, 1, ULONG_MAX, 0); + G_TEST (mul, unsigned long, ULONG_MAX, ULONG_MAX, 1); + + G_TEST (mul, unsigned long long, 0, 0, 0); + G_TEST (mul, unsigned long long, 0, ULLONG_MAX, 0); + G_TEST (mul, unsigned long long, 1, ULLONG_MAX, 0); + G_TEST (mul, unsigned long long, ULLONG_MAX, ULLONG_MAX, 1); + + /* Verify that each call to the type-specific __builtin_op_overflow + evaluates to a (not-necessarily constant) expression indicating + whether or not the constant expression (x op y) overflows. + The type-specific forms of the built-ins detect overflow after + arithmetic promotions and so unlike the type-generic overloads + cannot detect overflow in char or short types. */ + +#define T_TEST(op, T, x, y, vflow) \ + RuntimeAssert (op, T, __typeof__ ((x) + (y)), x, y, vflow) + + /* Signed int addition. */ + T_TEST (sadd, signed char, 0, 0, 0); + T_TEST (sadd, signed char, 0, SCHAR_MAX, 0); + T_TEST (sadd, signed char, 1, SCHAR_MAX, 0); + T_TEST (sadd, signed char, SCHAR_MAX, SCHAR_MAX, 0); + T_TEST (sadd, signed char, 0, SCHAR_MIN, 0); + T_TEST (sadd, signed char, -1, SCHAR_MIN, 0); + + T_TEST (sadd, short, 0, 0, 0); + T_TEST (sadd, short, 0, SHRT_MAX, 0); + T_TEST (sadd, short, 1, SHRT_MAX, 0); + T_TEST (sadd, short, SHRT_MAX, SHRT_MAX, 0); + T_TEST (sadd, short, 0, SHRT_MIN, 0); + T_TEST (sadd, short, -1, SHRT_MIN, 0); + T_TEST (sadd, short, SHRT_MIN, SHRT_MIN, 0); + + T_TEST (sadd, int, 0, 0, 0); + T_TEST (sadd, int, 0, INT_MAX, 0); + T_TEST (sadd, int, 1, INT_MAX, 1); + T_TEST (sadd, int, INT_MAX, INT_MAX, 1); + T_TEST (sadd, int, 0, INT_MIN, 0); + T_TEST (sadd, int, -1, INT_MIN, 1); + T_TEST (sadd, int, INT_MIN, INT_MIN, 1); + + /* Signed long addition. */ + T_TEST (saddl, long, 0L, 0L, 0); + T_TEST (saddl, long, 0L, LONG_MAX, 0); + T_TEST (saddl, long, 1L, LONG_MAX, 1); + T_TEST (saddl, long, LONG_MAX, LONG_MAX, 1); + T_TEST (saddl, long, 0L, LONG_MIN, 0); + T_TEST (saddl, long, -1L, LONG_MIN, 1); + T_TEST (saddl, long, LONG_MIN, LONG_MIN, 1); + + T_TEST (saddll, long long, 0LL, 0LL, 0); + T_TEST (saddll, long long, 0LL, LLONG_MAX, 0); + T_TEST (saddll, long long, 1LL, LLONG_MAX, 1); + T_TEST (saddll, long long, LLONG_MAX, LLONG_MAX, 1); + T_TEST (saddll, long long, 0LL, LLONG_MIN, 0); + T_TEST (saddll, long long, -1LL, LLONG_MIN, 1); + T_TEST (saddll, long long, LLONG_MIN, LLONG_MIN, 1); + + /* Unsigned int addition. */ + T_TEST (uadd, unsigned char, 0U, 0U, 0); + T_TEST (uadd, unsigned char, 0U, UCHAR_MAX, 0); + T_TEST (uadd, unsigned char, 1U, UCHAR_MAX, 0); + T_TEST (uadd, unsigned char, UCHAR_MAX, UCHAR_MAX, 0); + + T_TEST (uadd, unsigned short, 0U, 0U, 0); + T_TEST (uadd, unsigned short, 0U, USHRT_MAX, 0); + T_TEST (uadd, unsigned short, 1U, USHRT_MAX, 0); + T_TEST (uadd, unsigned short, USHRT_MAX, USHRT_MAX, 0); + + T_TEST (uadd, unsigned, 0U, 0U, 0); + T_TEST (uadd, unsigned, 0U, UINT_MAX, 0); + T_TEST (uadd, unsigned, 1U, UINT_MAX, 1); + T_TEST (uadd, unsigned, UINT_MAX, UINT_MAX, 1); + + /* Unsigned long addition. */ + T_TEST (uaddl, unsigned long, 0UL, 0UL, 0); + T_TEST (uaddl, unsigned long, 0UL, ULONG_MAX, 0); + T_TEST (uaddl, unsigned long, 1UL, ULONG_MAX, 1); + T_TEST (uaddl, unsigned long, ULONG_MAX, ULONG_MAX, 1); + + T_TEST (uaddll, unsigned long long, 0ULL, 0ULL, 0); + T_TEST (uaddll, unsigned long long, 0ULL, ULLONG_MAX, 0); + T_TEST (uaddll, unsigned long long, 1ULL, ULLONG_MAX, 1); + T_TEST (uaddll, unsigned long long, ULLONG_MAX, ULLONG_MAX, 1); + + /* Signed int subtraction. */ + T_TEST (ssub, signed char, 0, 0, 0); + T_TEST (ssub, signed char, 0, SCHAR_MAX, 0); + T_TEST (ssub, signed char, 1, SCHAR_MAX, 0); + T_TEST (ssub, signed char, SCHAR_MAX, SCHAR_MAX, 0); + T_TEST (ssub, signed char, 0, SCHAR_MIN, 0); + T_TEST (ssub, signed char, -1, SCHAR_MIN, 0); + + T_TEST (ssub, short, 0, 0, 0); + T_TEST (ssub, short, 0, SHRT_MAX, 0); + T_TEST (ssub, short, 1, SHRT_MAX, 0); + T_TEST (ssub, short, SHRT_MAX, SHRT_MAX, 0); + T_TEST (ssub, short, 0, SHRT_MIN, 0); + T_TEST (ssub, short, -1, SHRT_MIN, 0); + T_TEST (ssub, short, SHRT_MIN, SHRT_MIN, 0); + + T_TEST (ssub, int, 0, 0, 0); + T_TEST (ssub, int, 0, INT_MAX, 0); + T_TEST (ssub, int, 1, INT_MAX, 0); + T_TEST (ssub, int, INT_MAX, INT_MAX, 0); + T_TEST (ssub, int, 0, INT_MIN, 1); + T_TEST (ssub, int, -1, INT_MIN, 0); + T_TEST (ssub, int, INT_MIN, INT_MIN, 0); + + /* Signed long subtraction. */ + T_TEST (ssubl, long, 0L, 0L, 0); + T_TEST (ssubl, long, 0L, LONG_MAX, 0); + T_TEST (ssubl, long, 1L, LONG_MAX, 0); + T_TEST (ssubl, long, LONG_MAX, LONG_MAX, 0); + T_TEST (ssubl, long, 0L, LONG_MIN, 1); + T_TEST (ssubl, long, -1L, LONG_MIN, 0); + T_TEST (ssubl, long, LONG_MIN, LONG_MIN, 0); + + /* Signed long long subtraction. */ + T_TEST (ssubll, long long, 0LL, 0LL, 0); + T_TEST (ssubll, long long, 0LL, LLONG_MAX, 0); + T_TEST (ssubll, long long, 1LL, LLONG_MAX, 0); + T_TEST (ssubll, long long, LLONG_MAX, LLONG_MAX, 0); + T_TEST (ssubll, long long, 0LL, LLONG_MIN, 1); + T_TEST (ssubll, long long, -1LL, LLONG_MIN, 0); + T_TEST (ssubll, long long, LLONG_MIN, LLONG_MIN, 0); + + /* Unsigned int subtraction. */ + T_TEST (usub, unsigned char, 0U, 0U, 0); + T_TEST (usub, unsigned char, 0U, UCHAR_MAX, 1); + T_TEST (usub, unsigned char, 1U, UCHAR_MAX, 1); + T_TEST (usub, unsigned char, UCHAR_MAX, UCHAR_MAX, 0); + + T_TEST (usub, unsigned short, 0U, 0U, 0); + T_TEST (usub, unsigned short, 0U, USHRT_MAX, 1); + T_TEST (usub, unsigned short, 1U, USHRT_MAX, 1); + T_TEST (usub, unsigned short, USHRT_MAX, USHRT_MAX, 0); + + T_TEST (usub, unsigned, 0U, 0U, 0); + T_TEST (usub, unsigned, 0U, UINT_MAX, 1); + T_TEST (usub, unsigned, 1U, UINT_MAX, 1); + T_TEST (usub, unsigned, UINT_MAX, UINT_MAX, 0); + + /* Unsigned long subtraction. */ + T_TEST (usubl, unsigned long, 0UL, 0UL, 0); + T_TEST (usubl, unsigned long, 0UL, ULONG_MAX, 1); + T_TEST (usubl, unsigned long, 1UL, ULONG_MAX, 1); + T_TEST (usubl, unsigned long, ULONG_MAX, ULONG_MAX, 0); + + /* Unsigned long long subtraction. */ + T_TEST (usubll, unsigned long long, 0ULL, 0ULL, 0); + T_TEST (usubll, unsigned long long, 0ULL, ULLONG_MAX, 1); + T_TEST (usubll, unsigned long long, 1ULL, ULLONG_MAX, 1); + T_TEST (usubll, unsigned long long, ULLONG_MAX, ULLONG_MAX, 0); + + return 0; +} --- gcc/testsuite/g++.dg/cpp1y/constexpr-arith-overflow.C.jj 2016-06-06 11:37:40.771240464 +0200 +++ gcc/testsuite/g++.dg/cpp1y/constexpr-arith-overflow.C 2016-06-06 13:55:24.551263688 +0200 @@ -0,0 +1,229 @@ +// Test to exercise that the type-specific integer arithmetic built-ins +// with overflow checking can be used in C++ 14 constant expressions. +// -Woverflow is disabled to prevent (bogus?) G++ warnings. +// { dg-do compile { target c++14 } } +// { dg-additional-options "-Wno-overflow" } + +#define SCHAR_MAX __SCHAR_MAX__ +#define SHRT_MAX __SHRT_MAX__ +#define INT_MAX __INT_MAX__ +#define LONG_MAX __LONG_MAX__ +#define LLONG_MAX __LONG_LONG_MAX__ + +#define SCHAR_MIN (-__SCHAR_MAX__ - 1) +#define SHRT_MIN (-__SHRT_MAX__ - 1) +#define INT_MIN (-__INT_MAX__ - 1) +#define LONG_MIN (-__LONG_MAX__ - 1) +#define LLONG_MIN (-__LONG_LONG_MAX__ - 1) + +#define UCHAR_MAX (SCHAR_MAX * 2U + 1) +#define USHRT_MAX (SHRT_MAX * 2U + 1) +#define UINT_MAX (INT_MAX * 2U + 1) +#define ULONG_MAX (LONG_MAX * 2LU + 1) +#define ULLONG_MAX (LLONG_MAX * 2LLU + 1) + +#define USCHAR_MIN (-__USCHAR_MAX__ - 1) +#define USHRT_MIN (-__USHRT_MAX__ - 1) +#define UINT_MIN (-__UINT_MAX__ - 1) +#define ULONG_MIN (-__ULONG_MAX__ - 1) +#define ULLONG_MIN (-__ULONG_LONG_MAX__ - 1) + +// Helper macros. +#define sadd(x, y) ((x) + (y)) +#define saddl(x, y) ((x) + (y)) +#define saddll(x, y) ((x) + (y)) +#define uadd(x, y) ((x) + (y)) +#define uaddl(x, y) ((x) + (y)) +#define uaddll(x, y) ((x) + (y)) +#define ssub(x, y) ((x) - (y)) +#define ssubl(x, y) ((x) - (y)) +#define ssubll(x, y) ((x) - (y)) +#define usub(x, y) ((x) - (y)) +#define usubl(x, y) ((x) - (y)) +#define usubll(x, y) ((x) - (y)) +#define smul(x, y) ((x) * (y)) +#define smull(x, y) ((x) * (y)) +#define smulll(x, y) ((x) * (y)) +#define umul(x, y) ((x) * (y)) +#define umull(x, y) ((x) * (y)) +#define umulll(x, y) ((x) * (y)) + +// Result object. +template +struct Res +{ + constexpr Res (T a, bool v): z (a), v (v) { } + T z; bool v; +}; + +template +constexpr bool operator== (Res a, Res b) +{ + return a.z == b.z && a.v == b.v; +} + +#define StaticAssert(expr) static_assert ((expr), #expr) + +#define CONCAT(a, b) a ## b +#define CAT(a, b) CONCAT (a, b) + +// Helper to determine the type of the result of the arithmetic +// as specified by the built-ins. +template struct ResType { typedef T type; }; +template <> struct ResType { typedef int type; }; +template <> struct ResType { typedef unsigned type; }; +template <> struct ResType { typedef int type; }; +template <> struct ResType { typedef unsigned type; }; + +// Macro to define a single test case verifying that integer overflow +// is detected when expected, and when not, that the result matches +// the result computed using ordinary arithmetic. The result cannot +// be tested in the presence of overflow since it's not a core +// constant expression. +#define TEST(op, T, x, y, vflow) \ + constexpr Res CAT (op, __LINE__)(T a, T b) \ + { \ + ResType::type c = 0; \ + bool v = __builtin_ ## op ## _overflow (a, b, &c); \ + return Res(c, v); \ + } \ + StaticAssert (vflow ? CAT (op, __LINE__)(x, y).v \ + : CAT (op, __LINE__)(x, y) == Res(op (x, y), vflow)) + +/* Signed int addition. */ +TEST (sadd, signed char, 0, 0, 0); +TEST (sadd, signed char, 0, SCHAR_MAX, 0); +TEST (sadd, signed char, 1, SCHAR_MAX, 0); +TEST (sadd, signed char, SCHAR_MAX, SCHAR_MAX, 0); +TEST (sadd, signed char, 0, SCHAR_MIN, 0); +TEST (sadd, signed char, -1, SCHAR_MIN, 0); + +TEST (sadd, short, 0, 0, 0); +TEST (sadd, short, 0, SHRT_MAX, 0); +TEST (sadd, short, 1, SHRT_MAX, 0); +TEST (sadd, short, SHRT_MAX, SHRT_MAX, 0); +TEST (sadd, short, 0, SHRT_MIN, 0); +TEST (sadd, short, -1, SHRT_MIN, 0); +TEST (sadd, short, SHRT_MIN, SHRT_MIN, 0); + +TEST (sadd, int, 0, 0, 0); +TEST (sadd, int, 0, INT_MAX, 0); +TEST (sadd, int, 1, INT_MAX, 1); +TEST (sadd, int, INT_MAX, INT_MAX, 1); +TEST (sadd, int, 0, INT_MIN, 0); +TEST (sadd, int, -1, INT_MIN, 1); +TEST (sadd, int, INT_MIN, INT_MIN, 1); + +/* Signed long addition. */ +TEST (saddl, long, 0L, 0L, 0); +TEST (saddl, long, 0L, LONG_MAX, 0); +TEST (saddl, long, 1L, LONG_MAX, 1); +TEST (saddl, long, LONG_MAX, LONG_MAX, 1); +TEST (saddl, long, 0L, LONG_MIN, 0); +TEST (saddl, long, -1L, LONG_MIN, 1); +TEST (saddl, long, LONG_MIN, LONG_MIN, 1); + +TEST (saddll, long long, 0LL, 0LL, 0); +TEST (saddll, long long, 0LL, LLONG_MAX, 0); +TEST (saddll, long long, 1LL, LLONG_MAX, 1); +TEST (saddll, long long, LLONG_MAX, LLONG_MAX, 1); +TEST (saddll, long long, 0LL, LLONG_MIN, 0); +TEST (saddll, long long, -1LL, LLONG_MIN, 1); +TEST (saddll, long long, LLONG_MIN, LLONG_MIN, 1); + +/* Unsigned int addition. */ +TEST (uadd, unsigned char, 0U, 0U, 0); +TEST (uadd, unsigned char, 0U, UCHAR_MAX, 0); +TEST (uadd, unsigned char, 1U, UCHAR_MAX, 0); +TEST (uadd, unsigned char, UCHAR_MAX, UCHAR_MAX, 0); + +TEST (uadd, unsigned short, 0U, 0U, 0); +TEST (uadd, unsigned short, 0U, USHRT_MAX, 0); +TEST (uadd, unsigned short, 1U, USHRT_MAX, 0); +TEST (uadd, unsigned short, USHRT_MAX, USHRT_MAX, 0); + +TEST (uadd, unsigned, 0U, 0U, 0); +TEST (uadd, unsigned, 0U, UINT_MAX, 0); +TEST (uadd, unsigned, 1U, UINT_MAX, 1); +TEST (uadd, unsigned, UINT_MAX, UINT_MAX, 1); + +/* Unsigned long addition. */ +TEST (uaddl, unsigned long, 0UL, 0UL, 0); +TEST (uaddl, unsigned long, 0UL, ULONG_MAX, 0); +TEST (uaddl, unsigned long, 1UL, ULONG_MAX, 1); +TEST (uaddl, unsigned long, ULONG_MAX, ULONG_MAX, 1); + +TEST (uaddll, unsigned long long, 0ULL, 0ULL, 0); +TEST (uaddll, unsigned long long, 0ULL, ULLONG_MAX, 0); +TEST (uaddll, unsigned long long, 1ULL, ULLONG_MAX, 1); +TEST (uaddll, unsigned long long, ULLONG_MAX, ULLONG_MAX, 1); + +/* Signed int subtraction. */ +TEST (ssub, signed char, 0, 0, 0); +TEST (ssub, signed char, 0, SCHAR_MAX, 0); +TEST (ssub, signed char, 1, SCHAR_MAX, 0); +TEST (ssub, signed char, SCHAR_MAX, SCHAR_MAX, 0); +TEST (ssub, signed char, 0, SCHAR_MIN, 0); +TEST (ssub, signed char, -1, SCHAR_MIN, 0); + +TEST (ssub, short, 0, 0, 0); +TEST (ssub, short, 0, SHRT_MAX, 0); +TEST (ssub, short, 1, SHRT_MAX, 0); +TEST (ssub, short, SHRT_MAX, SHRT_MAX, 0); +TEST (ssub, short, 0, SHRT_MIN, 0); +TEST (ssub, short, -1, SHRT_MIN, 0); +TEST (ssub, short, SHRT_MIN, SHRT_MIN, 0); + +TEST (ssub, int, 0, 0, 0); +TEST (ssub, int, 0, INT_MAX, 0); +TEST (ssub, int, 1, INT_MAX, 0); +TEST (ssub, int, INT_MAX, INT_MAX, 0); +TEST (ssub, int, 0, INT_MIN, 1); +TEST (ssub, int, -1, INT_MIN, 0); +TEST (ssub, int, INT_MIN, INT_MIN, 0); + +/* Signed long subtraction. */ +TEST (ssubl, long, 0L, 0L, 0); +TEST (ssubl, long, 0L, LONG_MAX, 0); +TEST (ssubl, long, 1L, LONG_MAX, 0); +TEST (ssubl, long, LONG_MAX, LONG_MAX, 0); +TEST (ssubl, long, 0L, LONG_MIN, 1); +TEST (ssubl, long, -1L, LONG_MIN, 0); +TEST (ssubl, long, LONG_MIN, LONG_MIN, 0); + +/* Signed long long subtraction. */ +TEST (ssubll, long long, 0LL, 0LL, 0); +TEST (ssubll, long long, 0LL, LLONG_MAX, 0); +TEST (ssubll, long long, 1LL, LLONG_MAX, 0); +TEST (ssubll, long long, LLONG_MAX, LLONG_MAX, 0); +TEST (ssubll, long long, 0LL, LLONG_MIN, 1); +TEST (ssubll, long long, -1LL, LLONG_MIN, 0); +TEST (ssubll, long long, LLONG_MIN, LLONG_MIN, 0); + +/* Unsigned int subtraction. */ +TEST (usub, unsigned char, 0U, 0U, 0); +TEST (usub, unsigned char, 0U, UCHAR_MAX, 1); +TEST (usub, unsigned char, 1U, UCHAR_MAX, 1); +TEST (usub, unsigned char, UCHAR_MAX, UCHAR_MAX, 0); + +TEST (usub, unsigned short, 0U, 0U, 0); +TEST (usub, unsigned short, 0U, USHRT_MAX, 1); +TEST (usub, unsigned short, 1U, USHRT_MAX, 1); +TEST (usub, unsigned short, USHRT_MAX, USHRT_MAX, 0); + +TEST (usub, unsigned, 0U, 0U, 0); +TEST (usub, unsigned, 0U, UINT_MAX, 1); +TEST (usub, unsigned, 1U, UINT_MAX, 1); +TEST (usub, unsigned, UINT_MAX, UINT_MAX, 0); + +/* Unsigned long subtraction. */ +TEST (usubl, unsigned long, 0UL, 0UL, 0); +TEST (usubl, unsigned long, 0UL, ULONG_MAX, 1); +TEST (usubl, unsigned long, 1UL, ULONG_MAX, 1); +TEST (usubl, unsigned long, ULONG_MAX, ULONG_MAX, 0); + +/* Unsigned long long subtraction. */ +TEST (usubll, unsigned long long, 0ULL, 0ULL, 0); +TEST (usubll, unsigned long long, 0ULL, ULLONG_MAX, 1); +TEST (usubll, unsigned long long, 1ULL, ULLONG_MAX, 1); +TEST (usubll, unsigned long long, ULLONG_MAX, ULLONG_MAX, 0); --- gcc/testsuite/g++.dg/cpp0x/constexpr-arith-overflow.C.jj 2016-06-06 11:37:40.771240464 +0200 +++ gcc/testsuite/g++.dg/cpp0x/constexpr-arith-overflow.C 2016-06-06 13:01:55.928674227 +0200 @@ -0,0 +1,212 @@ +// PR c++/70507 - integer overflow builtins not constant expressions +// { dg-do compile { target c++11 } } + +#define SCHAR_MAX __SCHAR_MAX__ +#define SHRT_MAX __SHRT_MAX__ +#define INT_MAX __INT_MAX__ +#define LONG_MAX __LONG_MAX__ +#define LLONG_MAX __LONG_LONG_MAX__ + +#define SCHAR_MIN (-__SCHAR_MAX__ - 1) +#define SHRT_MIN (-__SHRT_MAX__ - 1) +#define INT_MIN (-__INT_MAX__ - 1) +#define LONG_MIN (-__LONG_MAX__ - 1) +#define LLONG_MIN (-__LONG_LONG_MAX__ - 1) + +#define UCHAR_MAX (SCHAR_MAX * 2U + 1) +#define USHRT_MAX (SHRT_MAX * 2U + 1) +#define UINT_MAX (INT_MAX * 2U + 1) +#define ULONG_MAX (LONG_MAX * 2LU + 1) +#define ULLONG_MAX (LLONG_MAX * 2LLU + 1) + +#define USCHAR_MIN (-__USCHAR_MAX__ - 1) +#define USHRT_MIN (-__USHRT_MAX__ - 1) +#define UINT_MIN (-__UINT_MAX__ - 1) +#define ULONG_MIN (-__ULONG_MAX__ - 1) +#define ULLONG_MIN (-__ULONG_LONG_MAX__ - 1) + +#define Assert(expr) static_assert ((expr), #expr) + +template +constexpr T add (T x, T y, T z = T ()) +{ + return __builtin_add_overflow (x, y, &z) ? 0 : z; +} + +template +constexpr T sub (T x, T y, T z = T ()) +{ + return __builtin_sub_overflow (x, y, &z) ? 0 : z; +} + +template +constexpr T mul (T x, T y, T z = T ()) +{ + return __builtin_mul_overflow (x, y, &z) ? 0 : z; +} + +#define TEST_ADD(T, x, y, z) Assert (z == add(x, y)) +#define TEST_SUB(T, x, y, z) Assert (z == sub(x, y)) +#define TEST_MUL(T, x, y, z) Assert (z == mul(x, y)) + + +TEST_ADD (signed char, 0, 0, 0); +TEST_ADD (signed char, 0, SCHAR_MAX, SCHAR_MAX); +TEST_ADD (signed char, 1, SCHAR_MAX, 0); // overflow +TEST_ADD (signed char, SCHAR_MAX, SCHAR_MAX, 0); // overflow +TEST_ADD (signed char, 0, SCHAR_MIN, SCHAR_MIN); +TEST_ADD (signed char, -1, SCHAR_MIN, 0); // overflow + +TEST_ADD (short, 0, 0, 0); +TEST_ADD (short, 0, SHRT_MAX, SHRT_MAX); +TEST_ADD (short, 1, SHRT_MAX, 0); // overflow +TEST_ADD (short, SHRT_MAX, SHRT_MAX, 0); // overflow +TEST_ADD (short, 0, SHRT_MIN, SHRT_MIN); +TEST_ADD (short, -1, SHRT_MIN, 0); // overflow +TEST_ADD (short, SHRT_MIN, SHRT_MIN, 0); // overflow + +TEST_ADD (int, 0, 0, 0); +TEST_ADD (int, 0, INT_MAX, INT_MAX); +TEST_ADD (int, 1, INT_MAX, 0); // overflow +TEST_ADD (int, INT_MAX, INT_MAX, 0); // overflow +TEST_ADD (int, 0, INT_MIN, INT_MIN); +TEST_ADD (int, -1, INT_MIN, 0); // overflow +TEST_ADD (int, INT_MIN, INT_MIN, 0); // overflow + +TEST_ADD (long, 0, 0, 0); +TEST_ADD (long, 0, LONG_MAX, LONG_MAX); +TEST_ADD (long, 1, LONG_MAX, 0); // overflow +TEST_ADD (long, LONG_MAX, LONG_MAX, 0); // overflow +TEST_ADD (long, 0, LONG_MIN, LONG_MIN); +TEST_ADD (long, -1, LONG_MIN, 0); // overflow +TEST_ADD (long, LONG_MIN, LONG_MIN, 0); // overflow + +TEST_ADD (long long, 0, 0, 0); +TEST_ADD (long long, 0, LLONG_MAX, LLONG_MAX); +TEST_ADD (long long, 1, LLONG_MAX, 0); // overflow +TEST_ADD (long long, LLONG_MAX, LLONG_MAX, 0); // overflow +TEST_ADD (long long, 0, LLONG_MIN, LLONG_MIN); +TEST_ADD (long long, -1, LLONG_MIN, 0); // overflow +TEST_ADD (long long, LLONG_MIN, LLONG_MIN, 0); // overflow + +TEST_ADD (unsigned char, 0, 0, 0); +TEST_ADD (unsigned char, 0, UCHAR_MAX, UCHAR_MAX); +TEST_ADD (unsigned char, 1, UCHAR_MAX, 0); // overflow + +TEST_ADD (unsigned char, UCHAR_MAX, UCHAR_MAX, 0); // overflow +TEST_ADD (unsigned short, 0, 0, 0); +TEST_ADD (unsigned short, 0, USHRT_MAX, USHRT_MAX); +TEST_ADD (unsigned short, 1, USHRT_MAX, 0); // overflow +TEST_ADD (unsigned short, USHRT_MAX, USHRT_MAX, 0); // overflow + +TEST_ADD (unsigned, 0, 0, 0); +TEST_ADD (unsigned, 0, UINT_MAX, UINT_MAX); +TEST_ADD (unsigned, 1, UINT_MAX, 0); // overflow +TEST_ADD (unsigned, UINT_MAX, UINT_MAX, 0); // overflow + +TEST_ADD (unsigned long, 0, 0, 0); +TEST_ADD (unsigned long, 0, ULONG_MAX, ULONG_MAX); +TEST_ADD (unsigned long, 1, ULONG_MAX, 0); // overflow +TEST_ADD (unsigned long, ULONG_MAX, ULONG_MAX, 0); // overflow + +TEST_ADD (unsigned long long, 0, 0, 0); +TEST_ADD (unsigned long long, 0, ULLONG_MAX, ULLONG_MAX); +TEST_ADD (unsigned long long, 1, ULLONG_MAX, 0); // overflow +TEST_ADD (unsigned long long, ULLONG_MAX, ULLONG_MAX, 0); // overflow + + +// Make sure the built-ins are accepted in the following contexts +// where constant expressions are required and that they return +// the expected overflow value. + +namespace Enum { + +enum Add { + a0 = __builtin_add_overflow_p ( 1, 1, 0), + a1 = __builtin_add_overflow_p (INT_MAX, 1, 0) +}; + +Assert (a0 == 0); +Assert (a1 == 1); + +enum Sub { + s0 = __builtin_sub_overflow_p ( 1, 1, 0), + s1 = __builtin_sub_overflow_p (INT_MIN, 1, 0) +}; + +Assert (s0 == 0); +Assert (s1 == 1); + +enum Mul { + m0 = __builtin_add_overflow_p ( 1, 1, 0), + m1 = __builtin_add_overflow_p (INT_MAX, INT_MAX, 0) +}; + +Assert (m0 == 0); +Assert (m1 == 1); + +} // namespace Enum + +namespace TemplateArg { + +template +struct Add { + Assert (z == v); +}; + +template +struct Sub { + Assert (z == v); +}; + +template +struct Mul { + Assert (z == v); +}; + +template struct Add; +template struct Add; + +template struct Sub; +template struct Sub; + +template struct Mul; +template struct Mul; + +} // namespace TemplateArg + +#if __cplusplus >= 201402L + +namespace Initializer { + +struct Result { + int res; + bool vflow; +}; + +constexpr Result +add_vflow (int a, int b) +{ +#if 1 + Result res = { a + b, __builtin_add_overflow_p (a, b, int ()) }; +#else + // The following fails to compile because of c++/71391 - error + // on aggregate initialization with side-effects in a constexpr + // function + int c = 0; + Result res = { 0, __builtin_add_overflow (a, b, &c) }; + res.c = c; +#endif + return res; +} + +constexpr Result sum = add_vflow (123, 456); +Assert (sum.res == 123 + 456); +Assert (!sum.vflow); + +} // namespace Initializer + +#endif // __cplusplus >= 201402L --- gcc/c/c-typeck.c.jj 2016-06-03 21:25:15.000000000 +0200 +++ gcc/c/c-typeck.c 2016-06-06 13:40:18.588949985 +0200 @@ -3150,6 +3150,7 @@ convert_arguments (location_t loc, vec