I've been looking through this Ada 95 tutorial. I was reading that it is possible to define a type that has a range that is different than the standard range, and if the program tries to go outside this range it will throw an error. While working on my own program I noticed that if the end of the range in the definition falls on the boundary for of its underlying type then the program will not raise the CONSTRAINT_ERROR when assigning values out of that range. Instead it will happily keep going and then wrap around. I wrote a program to explicitly show this.
Does anyone know of an Ada rule that explains this behavior?
-Kirk
Here is the output from my terminal, the source code is below that.
me@acheron:~/Dropbox/programs/ada$ gnatmake constraints.adb -f
gcc-4.6 -c constraints.adb
gnatbind -x constraints.ali
gnatlink constraints.ali
me@acheron:~/Dropbox/programs/ada$ ./constraints
Type ON has size: 7
It has a min/max of: 0 127
It's base has a min/max of: -128 127
Type UNDER has size: 7
It has a min/max of: 0 126
It's base has a min/max of: -128 127
The value of No_Error is: 245
raised CONSTRAINT_ERROR : constraints.adb:58 range check failed
me@acheron:~/Dropbox/programs/ada$
Source Code:
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;
Procedure Constraints is
type UNDER is range 0..126;
type ON is range 0..127;
type OVER is range 0..128;
Error : UNDER := 0;
No_Error : ON := 0;
Index : INTEGER := 0;
begin
New_Line;
Put("Type ON has size: ");
Put(INTEGER(ON'SIZE));
New_Line;
Put("It has a min/max of: ");
Put(INTEGER(ON'FIRST));
Put(INTEGER(ON'LAST));
New_Line;
Put("It's base has a min/max of: ");
Put(INTEGER(ON'BASE'FIRST));
Put(INTEGER(ON'BASE'LAST));
New_Line;
New_Line;
Put("Type UNDER has size: ");
Put(INTEGER(UNDER'SIZE));
New_Line;
Put("It has a min/max of: ");
Put(INTEGER(UNDER'FIRST));
Put(INTEGER(UNDER'LAST));
New_Line;
Put("It's base has a min/max of: ");
Put(INTEGER(UNDER'BASE'FIRST));
Put(INTEGER(UNDER'BASE'LAST));
Safe_Loop:
loop
No_Error := No_Error + 1;
Index := Index + 1;
--Put(INTEGER(No_Error));
exit Safe_Loop when Index = 245;
end loop Safe_Loop;
New_Line;
Put("The value of No_Error is: ");
Put(INTEGER(No_Error));
Index := 0;
Crash_Loop:
loop
Error := Error + 1;
Index := Index + 1;
exit Crash_Loop when Index = 245;
end loop Crash_Loop;
end Constraints;
According to the documentation:
Note again that
-gnato
is off by default, so overflow checking is not performed in default mode. This means that out of the box, with the default settings, GNAT does not do all the checks expected from the language description in the Ada Reference Manual. If you want all constraint checks to be performed, as described in this Manual, then you must explicitly use the -gnato switch either on thegnatmake
orgcc
command.
That said, the documentation also claims that:
Basically the rule is that in the default mode (
-gnato
not used), the generated code assures that all integer variables stay within their declared ranges, or within the base range if there is no declared range. This prevents any serious problems like indexes out of range for array operations. ¶ What is not checked in default mode is an overflow that results in an in-range, but incorrect value.
which seems to be wrong in the case you describe, since No_Error
really does end up completely outside its range. So this seems to go beyond "not […] expected from the language description" and into the realm of "compiler bug"; but at least you should be able to fix it by adding the -gnato
flag.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With