[fpc-devel] Progress on pure functions

J. Gareth Moreton gareth at moreton-family.com
Wed Aug 16 05:02:57 CEST 2023


So managed to stop the cascade in a fairly clean way (it detects the 
difference in ErrorCount, marks the call node as erroneous and flags 
"codegenerror"), and it seems to work.

pure1a.pp(15,24) Error: Range check error while evaluating constants 
(6227020800 must be between -2147483648 and 2147483647)
pure1a.pp(15,24) Error: At least 1 error(s) occurred during the purity 
analysis of subroutine "Factorial".
pure1a.pp(17) Fatal: There were 2 errors compiling module, stopping
Fatal: Compilation aborted

The message says "at least X error(s)" because other errors may get masked.

My recursive version of the factorial function doesn't quite simplify 
properly yet (it compiles successfully, but the call is a regular call 
and a warning is generated):

pure1b.pp(15,23) Warning: Subroutine "Factorial" is not eligible to be a 
pure function due to the following reason: analysis did not produce 
simple assignment.

Being a warning, this cascades and is generated multiple times (the 
number of times depends on how deep the recursion goes). I'll work on 
suppressing the cascade too since when this warning is triggered, the 
"pure" flag is removed from the subroutine.

Currently the "analysis did not produce simple assignment" part is a 
hard-coded string and not a part of errore.msg, for exmaple, so there 
may need to be a way to adapt this to be multi-lingual.

Kit

On 12/08/2023 18:14, J. Gareth Moreton via fpc-devel wrote:
> Hi everyone,
>
> So I'm still working on pure functions and have pushed some merge 
> requests that are indirectly related to it, mostly simplifying the 
> node tree so it can more easily be collapsed into simple assignments 
> (what pure functions should simplify to).  Negative testing is still 
> limited, but I have stumbled across one potential problem.  Using the 
> following code example:
>
> program pure1a;
> {$MODE OBJFPC}
> {$COPERATORS ON}
>
> function Factorial(N: Cardinal): Cardinal; pure;
>   var
>     X: Integer;
>   begin
>     Result := 1;
>     for X := N downto 2 do
>       Result *= X;
>   end;
>
> begin
>   WriteLn(Factorial(32));
> end.
>
> For those not familiar with the factorial function, the result 
> increases in value very quickly to the point that 13! > 2^32 
> (LongWord), 21! > 2^64 (QWord) and 70! > 10^100 (a googol), so 32! is 
> guaranteed to overflow.
>
> Having not really handled this eventuality just yet, I decided to see 
> what happens when the compiler runs it as is:
>
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (6227020800 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (27048749056 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (19184179200 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (32068960256 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (34071216128 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-288522240 must be between 0 and 4294967295)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (4006445056 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-5193400320 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-898433024 must be between 0 and 4294967295)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (3396534272 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-17070227456 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-2102132736 must be between 0 and 4294967295)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (2192834560 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-44144787456 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-1195114496 must be between 0 and 4294967295)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (3099852800 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-26292518912 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-522715136 must be between 0 and 4294967295)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (3772252160 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-12022448128 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (20698890240 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-775946240 must be between 0 and 4294967295)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (3519021056 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-19398656000 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (53980692480 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-1853882368 must be between 0 and 4294967295)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (2441084928 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-50054823936 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (41573941248 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-1375731712 must be between 0 and 4294967295)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (2919235584 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-39896219648 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-1241513984 must be between 0 and 4294967295)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (3053453312 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-37245419520 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (43687870464 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (23622320128 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Warning: Range check error while evaluating constants 
> (-2147483648 must be between 0 and 4294967295)
>
> Not an ideal cascade of warnings.  I figured it might be better to 
> throw an error instead, so during the processing of pure functions, I 
> enforced range and overflow checking:
>
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (6227020800 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (27048749056 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (19184179200 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (32068960256 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (34071216128 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-288522240 must be between 0 and 4294967295)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (4006445056 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-5193400320 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-898433024 must be between 0 and 4294967295)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (3396534272 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-17070227456 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (2192834560 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-2102132736 must be between 0 and 4294967295)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (2192834560 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-44144787456 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-1195114496 must be between 0 and 4294967295)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (3099852800 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-26292518912 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-522715136 must be between 0 and 4294967295)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (3772252160 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-12022448128 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (20698890240 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-775946240 must be between 0 and 4294967295)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (3519021056 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-19398656000 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (53980692480 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-1853882368 must be between 0 and 4294967295)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (2441084928 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-50054823936 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (41573941248 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-1375731712 must be between 0 and 4294967295)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (2919235584 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-39896219648 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-1241513984 must be between 0 and 4294967295)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (3053453312 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-37245419520 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (43687870464 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (23622320128 must be between -2147483648 and 2147483647)
> pure1a.pp(15,24) Error: Range check error while evaluating constants 
> (-2147483648 must be between 0 and 4294967295)
> pure1a.pp(17) Fatal: There were 39 errors compiling module, stopping
> Fatal: Compilation aborted
>
> This is not much better and is very unhelpful and untidy in an error 
> log.  Since the node tree is expanded during pure function analysis 
> (in this case, the for-loop is unrolled) and each node points to the 
> function call, each compiler message thus points here.  Ideally there 
> should only be one warning/error message, but since these messages are 
> generated elsewhere in the node compilation process, it's not that 
> easy to catch it and drop out the instant an error is thrown.
>
> So to ask.  If during analysis an overflow/range check error occurs, 
> how do you think it should be handled? And does anyone have tips on 
> how to program the compiler to immediately stop processing if a single 
> error is found or to otherwise suppress subsequent messages that point 
> to the same file location?
>
> Kit
>
> _______________________________________________
> fpc-devel maillist  -  fpc-devel at lists.freepascal.org
> https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel
>


More information about the fpc-devel mailing list