diff mbox

Go patch committed: Fix unary ^ on signed typed constant

Message ID mcrvcmpkv2f.fsf@dhcp-172-18-216-180.mtv.corp.google.com
State New
Headers show

Commit Message

Ian Lance Taylor March 1, 2012, 12:45 a.m. UTC
The Go frontend mishandled unary ^ applied to a signed typed integer
constant.  In fact it mishandled it so badly that it crashed.  This
patch fixes the problem.  Bootstrapped and ran Go testsuite on
x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

diff -r b66ddc182445 go/expressions.cc
--- a/go/expressions.cc	Wed Feb 29 15:41:26 2012 -0800
+++ b/go/expressions.cc	Wed Feb 29 16:43:14 2012 -0800
@@ -4300,14 +4300,23 @@ 
 	  unsigned HOST_WIDE_INT* phwi = new unsigned HOST_WIDE_INT[count];
 	  memset(phwi, 0, count * sizeof(HOST_WIDE_INT));
 
+	  size_t obits = utype->integer_type()->bits();
+
+	  if (!utype->integer_type()->is_unsigned()
+	      && mpz_sgn(uval) < 0)
+	    {
+	      mpz_t adj;
+	      mpz_init_set_ui(adj, 1);
+	      mpz_mul_2exp(adj, adj, obits);
+	      mpz_add(uval, uval, adj);
+	      mpz_clear(adj);
+	    }
+
 	  size_t ecount;
 	  mpz_export(phwi, &ecount, -1, sizeof(HOST_WIDE_INT), 0, 0, uval);
 	  go_assert(ecount <= count);
 
 	  // Trim down to the number of words required by the type.
-	  size_t obits = utype->integer_type()->bits();
-	  if (!utype->integer_type()->is_unsigned())
-	    ++obits;
 	  size_t ocount = ((obits + HOST_BITS_PER_WIDE_INT - 1)
 			   / HOST_BITS_PER_WIDE_INT);
 	  go_assert(ocount <= count);
@@ -4322,6 +4331,16 @@ 
 
 	  mpz_import(val, ocount, -1, sizeof(HOST_WIDE_INT), 0, 0, phwi);
 
+	  if (!utype->integer_type()->is_unsigned()
+	      && mpz_tstbit(val, obits - 1))
+	    {
+	      mpz_t adj;
+	      mpz_init_set_ui(adj, 1);
+	      mpz_mul_2exp(adj, adj, obits);
+	      mpz_sub(val, val, adj);
+	      mpz_clear(adj);
+	    }
+
 	  delete[] phwi;
 	}
       return Integer_expression::check_constant(val, utype, location);