From e6620e86376c650754216a2bf4601e76cf15e9c8 Mon Sep 17 00:00:00 2001 From: Kazu Hirata Date: Sat, 28 Jan 2006 05:19:44 +0000 Subject: [PATCH] re PR c/19606 (wrong code for arith.expr: (((unsigned int)(signed int) a ) / 2LL) with signed char a=-4) gcc/ PR c/19606. * c-typeck.c (build_binary_op): Perform implicit casts of operands before shortening them. gcc/testsuite/ PR c/19606. * gcc.c-torture/execute/pr19606.c: New. From-SVN: r110321 --- gcc/ChangeLog | 6 ++++ gcc/c-typeck.c | 31 ++++++++++++++--- gcc/testsuite/ChangeLog | 5 +++ gcc/testsuite/gcc.c-torture/execute/pr19606.c | 34 +++++++++++++++++++ 4 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/gcc.c-torture/execute/pr19606.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 16762cc9780..7c1baa3bd63 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2006-01-28 Kazu Hirata + + PR c/19606. + * c-typeck.c (build_binary_op): Perform implicit casts of + operands before shortening them. + 2006-01-27 H.J. Lu * df-scan.c (df_record_entry_block_defs): Check if diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index e1f78458146..ef518951c52 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -8101,12 +8101,35 @@ build_binary_op (enum tree_code code, tree orig_op0, tree orig_op1, if (shorten && none_complex) { int unsigned0, unsigned1; - tree arg0 = get_narrower (op0, &unsigned0); - tree arg1 = get_narrower (op1, &unsigned1); - /* UNS is 1 if the operation to be done is an unsigned one. */ - int uns = TYPE_UNSIGNED (result_type); + tree arg0, arg1; + int uns; tree type; + /* Cast OP0 and OP1 to RESULT_TYPE. Doing so prevents + excessive narrowing when we call get_narrower below. For + example, suppose that OP0 is of unsigned int extended + from signed char and that RESULT_TYPE is long long int. + If we explicitly cast OP0 to RESULT_TYPE, OP0 would look + like + + (long long int) (unsigned int) signed_char + + which get_narrower would narrow down to + + (unsigned int) signed char + + If we do not cast OP0 first, get_narrower would return + signed_char, which is inconsistent with the case of the + explicit cast. */ + op0 = convert (result_type, op0); + op1 = convert (result_type, op1); + + arg0 = get_narrower (op0, &unsigned0); + arg1 = get_narrower (op1, &unsigned1); + + /* UNS is 1 if the operation to be done is an unsigned one. */ + uns = TYPE_UNSIGNED (result_type); + final_type = result_type; /* Handle the case that OP0 (or OP1) does not *contain* a conversion diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 50cc3235b62..2f2f8c67727 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2006-01-28 Kazu Hirata + + PR c/19606. + * gcc.c-torture/execute/pr19606.c: New. + 2006-01-27 Carlos O'Donell * gcc.dg/pragma-re-4.c: New test. diff --git a/gcc/testsuite/gcc.c-torture/execute/pr19606.c b/gcc/testsuite/gcc.c-torture/execute/pr19606.c new file mode 100644 index 00000000000..d1e836fa028 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/pr19606.c @@ -0,0 +1,34 @@ +/* PR c/19606 + The C front end used to shorten the type of a division to a type + that does not preserve the semantics of the original computation. + Make sure that won't happen. */ + +signed char a = -4; + +int +foo (void) +{ + return ((unsigned int) (signed int) a) / 2LL; +} + +int +bar (void) +{ + return ((unsigned int) (signed int) a) % 5LL; +} + +int +main (void) +{ + int r; + + r = foo (); + if (r != ((unsigned int) (signed int) (signed char) -4) / 2LL) + abort (); + + r = bar (); + if (r != ((unsigned int) (signed int) (signed char) -4) % 5LL) + abort (); + + exit (0); +}