mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-21 14:30:59 +08:00
libfortran: fix conversion of UNSIGNED(kind=16) to decimal in output [PR118406]
PR libfortran/118406 libgfortran/ChangeLog: * runtime/string.c (gfc_itoa): Handle unsigned integers larger than (10^19 * 2^64). gcc/testsuite/ChangeLog: * gfortran.dg/unsigned_write.f90: New test.
This commit is contained in:
parent
1ff85affe4
commit
99bcce0d89
40
gcc/testsuite/gfortran.dg/unsigned_write.f90
Normal file
40
gcc/testsuite/gfortran.dg/unsigned_write.f90
Normal file
@ -0,0 +1,40 @@
|
||||
! { dg-do run }
|
||||
! This is a libgfortran (runtime library) test, need to run only once!
|
||||
!
|
||||
! { dg-require-effective-target fortran_integer_16 }
|
||||
! { dg-additional-options "-funsigned" }
|
||||
!
|
||||
! PR libfortran/118406 - printing large UNSIGNED(kind=16) crashes
|
||||
|
||||
program print_large_unsigned
|
||||
unsigned(16), parameter :: u16_max = huge(0U_16)
|
||||
unsigned(16), parameter :: u8_max = uint(huge(0U_8),16) ! UINT64_MAX
|
||||
unsigned(16), parameter :: ten19 = uint(10_8 ** 18,16)*10U_16 ! 10**19
|
||||
character(42) :: s
|
||||
|
||||
! Reference: signed integer
|
||||
write(s,*) huge(0_16)
|
||||
if (adjustl (s) /= "170141183460469231731687303715884105727") stop 1
|
||||
|
||||
! Same value as unsigned
|
||||
write(s,*) uint (huge(0_16),16)
|
||||
if (adjustl (s) /= "170141183460469231731687303715884105727") stop 2
|
||||
|
||||
! Extreme and intermediate values
|
||||
write(s,*) u16_max
|
||||
if (adjustl (s) /= "340282366920938463463374607431768211455") stop 3
|
||||
|
||||
write(s,*) (u16_max - 3U_16) / 4U_16 * 3U_16
|
||||
if (adjustl (s) /= "255211775190703847597530955573826158589") stop 4
|
||||
|
||||
! Test branches of implementation in string.c::gfc_itoa
|
||||
write(s,*) u8_max * ten19
|
||||
if (adjustl (s) /= "184467440737095516150000000000000000000") stop 5
|
||||
|
||||
write(s,*) u8_max * ten19 - 1U_16
|
||||
if (adjustl (s) /= "184467440737095516149999999999999999999") stop 6
|
||||
|
||||
write(s,*) u8_max * ten19 + 1U_16
|
||||
if (adjustl (s) /= "184467440737095516150000000000000000001") stop 7
|
||||
|
||||
end
|
@ -241,18 +241,35 @@ gfc_itoa (GFC_UINTEGER_LARGEST n, char *buffer, size_t len)
|
||||
the uint64_t function are not sufficient for all 128-bit unsigned
|
||||
integers (we would need three calls), but they do suffice for all
|
||||
values up to 2^127, which is the largest that Fortran can produce
|
||||
(-HUGE(0_16)-1) with its signed integer types. */
|
||||
(-HUGE(0_16)-1) with its signed integer types.
|
||||
With the introduction of UNSIGNED integers, we must treat the case
|
||||
of unsigned ints larger than (10^19 * 2^64) by adding one step. */
|
||||
_Static_assert (sizeof(GFC_UINTEGER_LARGEST) <= 2 * sizeof(uint64_t),
|
||||
"integer too large");
|
||||
|
||||
GFC_UINTEGER_LARGEST r;
|
||||
r = n % TEN19;
|
||||
n = n / TEN19;
|
||||
assert (r <= UINT64_MAX);
|
||||
p = itoa64_pad19 (r, p);
|
||||
if (n <= TEN19 * UINT64_MAX)
|
||||
{
|
||||
GFC_UINTEGER_LARGEST r;
|
||||
r = n % TEN19;
|
||||
n = n / TEN19;
|
||||
assert (r <= UINT64_MAX);
|
||||
p = itoa64_pad19 (r, p);
|
||||
|
||||
assert(n <= UINT64_MAX);
|
||||
return itoa64 (n, p);
|
||||
assert(n <= UINT64_MAX);
|
||||
return itoa64 (n, p);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Here n > (10^19 * 2^64). */
|
||||
GFC_UINTEGER_LARGEST d1, r1, d2, r2;
|
||||
d1 = n / (TEN19 * TEN19);
|
||||
r1 = n % (TEN19 * TEN19);
|
||||
d2 = r1 / TEN19;
|
||||
r2 = r1 % TEN19;
|
||||
p = itoa64_pad19 (r2, p);
|
||||
p = itoa64_pad19 (d2, p);
|
||||
return itoa64 (d1, p);
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* On targets where the largest integer is 64-bit, just use that. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user