From e6620e86376c650754216a2bf4601e76cf15e9c8 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu@codesourcery.com>
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 16762cc9780b..7c1baa3bd637 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2006-01-28  Kazu Hirata  <kazu@codesourcery.com>
+
+	PR c/19606.
+	* c-typeck.c (build_binary_op): Perform implicit casts of
+	operands before shortening them.
+
 2006-01-27  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* df-scan.c (df_record_entry_block_defs): Check if
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index e1f784581463..ef518951c52f 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 50cc3235b621..2f2f8c67727c 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2006-01-28  Kazu Hirata  <kazu@codesourcery.com>
+
+	PR c/19606.
+	* gcc.c-torture/execute/pr19606.c: New.
+
 2006-01-27  Carlos O'Donell  <carlos@codesourcery.com>
 
 	* 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 000000000000..d1e836fa028a
--- /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);
+}
-- 
GitLab