Recent

Author Topic: unexpected qword range check warning  (Read 1517 times)

440bx

  • Hero Member
  • *****
  • Posts: 3946
unexpected qword range check warning
« on: September 09, 2018, 06:14:16 am »
hello,

I'm getting a range check warning that seems superfluous/invalid.
Code: Pascal  [Select][+][-]
  1. Compile Project, Mode: Win64, OS: win64, CPU: x86_64, Target: _QwordRangeCheck.exe: Success, Warnings: 1
  2. _QwordRangeCheck.lpr(43,38) Warning: range check error while evaluating constants (-1 must be between 0 and 18446744073709551615)
  3.  

In the simple program below, when the maximum value for a qword is passed to the function, the compiler issues a warning stating that the constant is out of range but, when passing the same value in decimal, there is no such warning. 

Is there a good reason for the discrepancy or should this behavior be considered a bug ?

Sample program:
Code: Pascal  [Select][+][-]
  1. {$MODE OBJFPC                      }
  2.  
  3. {$MODESWITCH     ADVANCEDRECORDS   }
  4. {$MODESWITCH     TYPEHELPERS       }
  5. {$MODESWITCH     ALLOWINLINE       }
  6. {$MODESWITCH     RESULT            }
  7. {$MODESWITCH     PROPERTIES        }
  8.  
  9. {$MODESWITCH     ANSISTRINGS-      }
  10. {$MODESWITCH     AUTODEREF-        }
  11. {$MODESWITCH     UNICODESTRINGS-   }
  12. {$MODESWITCH     POINTERTOPROCVAR- }
  13.  
  14. {$LONGSTRINGS    OFF               }
  15. {$WRITEABLECONST ON                }
  16. {$TYPEDADDRESS   ON                }
  17.  
  18.  
  19.  
  20. program _QwordRangeCheck;
  21.  
  22. function  DecDigits (value : qword) : word;
  23. var
  24.   commas : integer;
  25.  
  26. begin
  27.   result := 0;
  28.  
  29.   repeat
  30.     inc(result);
  31.     value  := value div 10;
  32.   until value = 0;
  33.  
  34.   commas := result div 3;
  35.  
  36.   if result mod 3 = 0 then dec(commas);
  37.  
  38.   result += commas;
  39. end;
  40.  
  41.  
  42. begin
  43.   writeln(DecDigits($FFFFFFFFFFFFFFFF));            // range check warning
  44.  
  45.   writeln;
  46.  
  47.   //   18446744073709551615                         // max qword
  48.  
  49.   writeln(DecDigits(18446744073709551615));         // NO range check warning
  50. end.
  51.  

Thank you.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 14205
  • Probably until I exterminate Putin.
Re: unexpected qword range check warning
« Reply #1 on: September 09, 2018, 06:34:07 am »
Literal values in hex notation are of a signed type. I believe this is documented somewhere.(but can't find it quickly now)
As can be seen when you add these:
Code: Pascal  [Select][+][-]
  1. var
  2.   t:qword =  qword($FFFFFFFFFFFFFFFF); //without cast, it is int64 this is delphi compatible.
  3. begin
  4.   writeln(DecDigits(T));
  5.  
One reason is probably Delphi compatibility. Older Delphi's didn't have a true uint64 type.
Then there is of course the ambiguity that is inherent for a literal in hex. The compiler chooses signed...could have been unsigned, which causes the reverse problem..
Code: Pascal  [Select][+][-]
  1. // this reveals it:
  2. {$mode delphi}
  3. begin
  4.   writeln(GetTypeKind($FFFFFFFFFFFFFFFF)); // tkInteger ....
  5. end.
Note I filed a bug against GetTypeKind returning tkInteger. It should of course return tkInt64 but that's another matter.
Safe to say a literal hex value is a signed value by default.

[edit]
Marco informed me that since $FFFFFFFFFFFFFFFF equals -1 the compiler can encode it as an integer that can hold -1, so the default 32 bit integer type is OK.
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode delphi}{$H+}{$endif}
  2. program testintlit;
  3. begin
  4.  // all these print tkInteger, so the literal type is a signed integer.
  5.  writeln(gettypekind($f));               // nibble
  6.  writeln(gettypekind($ff));              // byte or shortint
  7.  writeln(gettypekind($ffff));            // word or smallint
  8.  writeln(gettypekind($ffffffff));        // dword or integer (32)
  9.  writeln(gettypekind($ffffffffffffffff));// qword or int64
  10. end.
Note this is only the case for literals: the typekind of a variable is always the typekind of the declared size and sign.
But a qword sized hex literal still needs a cast to qword($ffffffffffffffff) or High(qword) instead of $ffffffffffffffff .
« Last Edit: September 09, 2018, 04:01:44 pm by Thaddy »
Specialize a type, not a var.

 

TinyPortal © 2005-2018