Can someone help me understand why GNAT is warning me that the following code could raise a Constraint_Error?
function Test_Function (Test_Input : Boolean) return Boolean is
begin
if Test_Input then
return False;
else
return True;
end if;
end Test_Function;
I’m working with a ZFP runtime, with pragma Restrictions (No_Exception_Propagation), and GNAT gives me the following error at compile time:
utilities.adb:22:10: warning: pragma Restrictions (No_Exception_Propagation) in effect [-gnatw.x]
utilities.adb:22:10: warning: "Constraint_Error" may call Last_Chance_Handler [-gnatw.x]
To me it looks impossible for this to ever cause a constraint error, as the compiler would catch any attempt to call the function with a non-Boolean parameter, and the return values are both Boolean literals.
Boolean is implemented as an enum type Boolean is (False, True); so Normalize_Scalars would initialize it with all bits 1… GCC won’t pack anything smaller than 8 bits unless you tell it not to, so this would be 255, which is definitely not True or False.
Thanks for your reply! pragma Normalize_Scalars isn’t set anywhere in my project. If you set it compilation will actually fail, because it looks like the light-rv64imafdc runtime I’m using wasn’t compiled with Normalize_Scalars.
pragma Restrictions (No_Exception_Propagation);
procedure Hello is
function Test_Function (Test_Input : Boolean) return Boolean is
begin
if Test_Input then
return False;
else
return True;
end if;
end Test_Function;
Fake_Bool : Boolean := True;
begin
Fake_Bool := Test_Function(Fake_Bool);
null;
end Hello;
And it compiles with no warnings, issues or complains. GNATprove also says nothing! What compiler version are you using? Could you show all the code?
There really isn’t any more of my code to show.
I’m compiling with gnat_riscv64_elf version 14.2.1, using the light-rv64imafdc runtime. I’m compiling with "-gnatwadehl", so all warnings are treated as errors.
Can you try recreating it with pragma Restrictions (No_Exception_Propagation); enabled? I created a minimal reproducible example, and this restriction is the magic ingredient to triggering the error, which makes sense.
No, I’m never actually calling this function. All I need to do to trigger the compilation error is define it. The error points to the line: if Test_Input then.
It is not a magic ingredient, it activates warning when restrictions applied, because exception propagation is not supported by runtime, and last chance handler is called directly. For runtimes with support of exception propagation exception is raised and propagated out of the subprogram.
The crazy thing is that you can prove this function correct using SPARK, but when treating warnings as errors, it won’t compile because of the warning about exception propagation.
Maybe a very nieve answer that skips over the ZFP aspect. Is Test_Input declared and initialized somewhere (in scope/visible to Test_Function) before it’s passed as a parameter into Test_Function, say in a spec/declaration somewhere, if not in the calling code?
If so,
(1) you have the answer without even needing Test_Function.
(2) code is just: function Test_Function(Test_Input: in out boolean) return boolean is…
…
return Test_Input; — ridiculously redundant
As another noted boolean is an enumeration type anyway. Maybe test ZFP some other way and not argue with/or question what the compiler is whining about. For little me, when Mr. Compiler complains, I just listen, and believe it, as it is what it is and does what it does and it’s easier, for me, just to go along and complete my higher goal, when there is one.
Yes, I do actually. If you remove this compiler flag the warning isn’t generated.
Thank you for pointing this out! I’ll investigate this further.
The GPR file for this project has been inherited from another old project. I don’t know why these particular compilation switches were chosen. I think they were just chosen to set the strictness to the maximum.
Test_Input is a function argument, not a global variable. It’s not set anywhere else. I understand how to suppress the warning by explicitly handling the exception. I’m just confused under what conditions could a boolean generate a Constraint_Error. Is the compiler not assuming that Test_Input has a semantically valid value when the function is called?
Here’s another interesting problem I’ve encountered after removing the extra validity checks:
function Test_Divide (Test_Natural : Natural) return Natural is
begin
return Test_Natural / 32;
exception
when Constraint_Error =>
return 0;
end Test_Divide;
When compiling this code with gnat_riscv64_elf = “^15.2.1”, and the light-rv64imafdc runtime, this code will fail with the following error: test.adb:19:07: warning: pragma Restrictions (No_Exception_Propagation) in effect [-gnatw.x] test.adb:19:07: warning: this handler can never be entered, and has been removed [-gnatw.x]
Remove the exception handling block, and it fails with the opposite error: test.adb:17:27: warning: pragma Restrictions (No_Exception_Propagation) in effect [-gnatw.x] test.adb:17:27: warning: “Constraint_Error” may call Last_Chance_Handler [-gnatw.x]
Compiling with the native GNAT compiler for Linux x86-64, I don’t encounter this problem. It correctly determines that this code can raise a constraint error at runtime.
What am I missing here? Any pointers would be appreciated.