Constraint_Error raised when using modular types not divisble by 8

With recent GNATs, you can achieve the behaviour you want by defining Buffer_Type_Two as

type Buffer_Type_Two is array (1 .. 128) of Type_Two
  with Pack;

ARM 13.2(9) warns that this may not do what you want for 13-bit values (recent GNATs do, though).

An alternative would be

type Buffer_Type_Two is array (1 .. 128) of Type_Two
  with Component_Size => 12;

The results are

...
Testing type two
Test:  32
Test:  514
Test:  32
Test:  514
...

For 13 bits, with either approach,

...
Testing type two
Test:  32
Test:  257
Test:  2056
Test:  64
Test:  514
Test:  4112
Test:  128
Test:  1028
Test:  32
...

HOWEVER, for an embedded target, you’ll need to use the -full- runtime system; for others, as pointed out by @egilhh above,

ajxs.adb:14:09: packing of 12-bit components not supported by configuration

Considering the compilation warnings, the code didn’t really deserve to work ...

31.          Buffer_One : Buffer_Type_One
32.            with Import,
33.              Convention => Ada,
34.              Address    => Test_Buffer'Address;
                 |
    >>> warning: specified address for "Buffer_One" may be inconsistent with alignment
    >>> warning: program execution may be erroneous (RM 13.3(27))
    >>> warning: alignment of "Buffer_One" is 2
    >>> warning: alignment of "Test_Buffer" is 1

and

49.          Buffer_Two : Buffer_Type_Two
50.            with Import,
51.              Convention => Ada,
52.              Address    => Test_Buffer'Address;
                 |
    >>> warning: specified address for "Buffer_Two" may be inconsistent with alignment
    >>> warning: program execution may be erroneous (RM 13.3(27))
    >>> warning: alignment of "Buffer_Two" is 2
    >>> warning: alignment of "Test_Buffer" is 1

but that’s not the problem, as it happens: Type_Two is mod 2**12, i.e. mod 4096, but the value in Buffer_Two(1) is 16#2020# (two space characters), which is 8224 in decimal.

"But why isn’t the stored value automatically masked to the 12 bits I asked for?" you say. For reasons of efficiency, "the size of an object is not necessarily the same as the size of the type of [the] object", GNAT RM 4.43, and GNAT expects the spare 4 bits at the top of the 16-bit word to be zero. On its own, a value of type Type_Two occupies (has ’Object_Size of) 16 bits. You could get the 12-bit size you want by including the Type_Two field in a record and specifying its layout, but that does add complication.

The problem wasn’t detected here without the -gnatVa (turn on all validity checking options).


The physical value of 16#2020# is not in the range of Type_Two so Constraint_Error is expected with -gnatVa.

GNAT CE 2020 raises Constraint_Error.

Uncommenting the exception/when part leads to further information:

raised CONSTRAINT_ERROR : main.adb:51 invalid data

Tags:

Ada

Gnat