Search code examples
gccadagnat

Unexpected CONSTRAINT_ERROR after GCC update


We recently updated GCC versions (4.8.2 to 5.3.0) and started receiving unexpected constraint errors in some Ada applications. I've reduced it to the following:

-- moo.adb
with text_io;
procedure moo is
   type thing_type is (something1,something2,something3,something4,something5,something6);
   for thing_type use (something1 => 1,something2 => 2,something3 => 
      3,something4 => 4,something5 => 5,something6 => 6);
   for thing_type'size use 32;
   type thing_array_t is array (0 .. 5) of thing_type;
   thing_array : thing_array_t := (others => something1);
begin
   text_io.put_line("item 0 = " & thing_type'image(thing_array(0)));
end moo;

This program will compile just fine on either GCC version (simply compiled with "gnatmake moo.adb".) When built with 4.8.2, the output is as expected:

item 0 = SOMETHING1

When built with 5.0.3, we instead receive

raised CONSTRAINT_ERROR : moo.adb:13 invalid data

Interestingly, the results are exactly the same when compiled as 32 and 64 bit. Many things can be changed to make the program work fine with 5.3.0: removing the thing_type'size clause, adding or removing values to the enumerator, changing the number of items in the array, using a different value for initializing the array, etc. Are there any obvious problems with this code that could account for this behavior?


Solution

  • This bug is still present in GCC 7.0.1. Running under the debugger, output slightly edited,

    (gdb) catch exception
    Catchpoint 2: all Ada exceptions
    (gdb) run
    Starting program: /Users/simon/tmp/so/moo 
    [New Thread 0x1703 of process 75511]
    
    Catchpoint 2, CONSTRAINT_ERROR (moo.adb:10 invalid data) at 0x0000000100001abe in _ada_moo () at moo.adb:10
    10     text_io.put_line("item 0 = " & thing_type'image(thing_array(0)));
    (gdb) p thing_array
    $5 = (0 => 16843009, 16843009, 16843009, 16843009, 16843009, 16843009)
    (gdb) p/x thing_array
    $6 = (0 => 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101, 0x1010101)
    

    so GNAT has mistakenly set each byte of thing_array elements to 16#01#, rather than the whole element.

    The same happens if something1 is set to 2 (and later values incremented, likewise).

    The only thing I can find that helps is to declare, for example,

    type base_thing_type is (invalid, something1,something2,something3,something4,something5,something6);
    for base_thing_type use (invalid => 0, something1 => 1,something2 => 2,something3 =>
                          3,something4 => 4,something5 => 5,something6 => 6);
    for base_thing_type'size use 32;
    type thing_type is new base_thing_type range something1 .. something6;