Support text format for integer fields wider than 64 bits

DecodeInteger gated its handling of a leading '-' on ::std::is_signed<IntType>,
which is false for __int128_t under a strict -std=c++NN.  As a result a
negative value could not be parsed into a signed field wider than 64 bits (the
'-' was treated as an invalid character and parsing failed), even though the
same value encodes fine on the way out.  Use ::std::numeric_limits<>::is_signed
instead, matching the fix applied to IntView::CouldWriteValue.

Add text-format round-trip tests for values that do not fit in 64 bits,
including a negative value into a >64-bit signed field and rejection of an
out-of-range text value.
diff --git a/compiler/back_end/cpp/testcode/int128_sizes_test.cc b/compiler/back_end/cpp/testcode/int128_sizes_test.cc
index 9412b35..33091fd 100644
--- a/compiler/back_end/cpp/testcode/int128_sizes_test.cc
+++ b/compiler/back_end/cpp/testcode/int128_sizes_test.cc
@@ -356,6 +356,52 @@
   EXPECT_EQ(x.sixteen_byte().Read(), y.sixteen_byte().Read());
 }
 
+// Text format must round-trip values that do not fit in 64 bits, in both
+// directions.  Parsing a negative value into a >64-bit signed field in
+// particular exercises the signedness check in DecodeInteger.
+TEST(UInt128SizesView, TextFormatRoundTrip) {
+  ::std::uint8_t buffer[100] = {};
+  auto writer = UInt128SizesWriter(buffer, sizeof buffer);
+
+  // A 128-bit value that does not fit in 64 bits.
+  EXPECT_TRUE(::emboss::UpdateFromText(
+      writer, "{sixteen_byte: 0xfedcba98765432100123456789abcdef}"));
+  __uint128_t expected =
+      (static_cast<__uint128_t>(0xfedcba9876543210UL) << 64) |
+      static_cast<__uint128_t>(0x0123456789abcdefUL);
+  EXPECT_EQ(expected, writer.sixteen_byte().Read());
+
+  // Out-of-range text for a 72-bit field must be rejected, not crash.
+  EXPECT_FALSE(::emboss::UpdateFromText(
+      writer, "{nine_byte: 0x1000000000000000000}"));  // 2**72
+}
+
+TEST(Int128SizesView, TextFormatRoundTripNegative) {
+  ::std::uint8_t buffer[100] = {};
+  auto writer = Int128SizesWriter(buffer, sizeof buffer);
+
+  // Negative value into a 72-bit signed field: the '-' must be honored even
+  // though ::std::is_signed<__int128_t> is false under a strict -std.
+  EXPECT_TRUE(::emboss::UpdateFromText(writer, "{nine_byte: -12345}"));
+  EXPECT_EQ(static_cast<__int128_t>(-12345), writer.nine_byte().Read());
+
+  // A large negative 128-bit value (-2**120) does not fit in 64 bits; it must
+  // round-trip through the decimal text format.
+  EXPECT_TRUE(::emboss::UpdateFromText(
+      writer, "{sixteen_byte: -1329227995784915872903807060280344576}"));
+  EXPECT_EQ(-(static_cast<__int128_t>(1) << 120), writer.sixteen_byte().Read());
+
+  // Round-trip through WriteToString and back.
+  ::std::string text = ::emboss::WriteToString(
+      MakeInt128SizesView(buffer, sizeof buffer));
+  ::std::uint8_t buffer2[100] = {};
+  auto writer2 = Int128SizesWriter(buffer2, sizeof buffer2);
+  EXPECT_TRUE(::emboss::UpdateFromText(writer2, text));
+  EXPECT_EQ(-(static_cast<__int128_t>(1) << 120),
+            writer2.sixteen_byte().Read());
+  EXPECT_EQ(static_cast<__int128_t>(-12345), writer2.nine_byte().Read());
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace emboss
diff --git a/runtime/cpp/emboss_text_util.h b/runtime/cpp/emboss_text_util.h
index 9cfe03d..061ea31 100644
--- a/runtime/cpp/emboss_text_util.h
+++ b/runtime/cpp/emboss_text_util.h
@@ -132,7 +132,11 @@
   IntType base = 10;
   bool negative = false;
   unsigned offset = 0;
-  if (::std::is_signed<IntType>::value && text.size() >= 1 + offset &&
+  // ::std::numeric_limits<>::is_signed is used rather than ::std::is_signed<>
+  // because the latter is false for extended integer types such as __int128_t
+  // under a strict -std=c++NN, which would prevent parsing negative values into
+  // those types.  numeric_limits *is* specialized for them.
+  if (::std::numeric_limits<IntType>::is_signed && text.size() >= 1 + offset &&
       text[offset] == '-') {
     negative = true;
     offset += 1;