Recent

Author Topic: Implicit converison, literals and QWORD variable warning  (Read 2783 times)

julkas

  • Guest
Implicit converison, literals and QWORD variable warning
« on: August 06, 2020, 06:14:05 pm »
Same code on Windows 10 64bit and FPC, Delphi output -
Code: Pascal  [Select][+][-]
  1. program consta;
  2. {$IFDEF FPC}
  3. {$MODE Delphi}
  4. {$ENDIF}
  5. uses SysUtils;
  6.  
  7. const
  8.   c64_1         = $FFFFFFFFFFFFFFFF;
  9.   c64_2  = UInt64($FFFFFFFFFFFFFFFF);
  10.   c64_3: UInt64 = $FFFFFFFFFFFFFFFF;
  11.  
  12. var
  13.   v64: UInt64 = c64_1;
  14.  
  15. begin
  16.   WriteLn(Format('c64_1: %x - %u', [c64_1, c64_1]));   
  17.   if c64_1 < 0 then
  18.     WriteLn('c64_1 < 0');
  19.   WriteLn(Format('c64_2: %x - %u', [c64_2, c64_2]));   
  20.   if c64_2 < 0 then
  21.     WriteLn('c64_2 < 0');
  22.   WriteLn(Format('c64_3: %x - %u', [c64_3, c64_3]));   
  23.   if c64_3 < 0 then
  24.     WriteLn('c64_3 < 0');      
  25.  
  26.   WriteLn(Format('v64  : %x - %u', [v64, v64]));       
  27.   if v64 < 0 then
  28.     WriteLn('v64 < 0');
  29.        
  30. end.
  31.  

FPC output -
Code: Bash  [Select][+][-]
  1. $ fpc -B consta.pas
  2. Free Pascal Compiler version 3.0.4 [2020/04/11] for x86_64
  3. Copyright (c) 1993-2017 by Florian Klaempfl and others
  4. Target OS: Win64 for x64
  5. Compiling consta.pas
  6. consta.pas(10,36) Warning: range check error while evaluating constants (-1 must be between 0 and 18446744073709551615)
  7. consta.pas(13,22) Warning: range check error while evaluating constants (-1 must be between 0 and 18446744073709551615)
  8. consta.pas(21,5) Warning: unreachable code
  9. consta.pas(23,12) Warning: Comparison might be always false due to range of constant and expression
  10. consta.pas(24,5) Warning: unreachable code
  11. consta.pas(27,10) Warning: Comparison might be always false due to range of constant and expression
  12. consta.pas(28,5) Warning: unreachable code
  13. Linking consta.exe
  14. 29 lines compiled, 0.2 sec, 71488 bytes code, 4932 bytes data
  15. 7 warning(s) issued
  16.  
  17. $ ./consta.exe
  18. c64_1: FFFFFFFF - 4294967295
  19. c64_1 < 0
  20. c64_2: FFFFFFFFFFFFFFFF - 18446744073709551615
  21. c64_3: FFFFFFFFFFFFFFFF - 18446744073709551615
  22. v64  : FFFFFFFFFFFFFFFF - 18446744073709551615
  23.  

Delphi output -
Code: Bash  [Select][+][-]
  1. $ dcc64 -B -NSSystem consta.pas
  2. Embarcadero Delphi for Win64 compiler version 33.0
  3. Copyright (c) 1983,2018 Embarcadero Technologies, Inc.
  4. consta.pas(30)
  5. 31 lines, 0.09 seconds, 175348 bytes code, 63152 bytes data.
  6.  
  7. $ ./consta.exe
  8. c64_1: FFFFFFFFFFFFFFFF - 18446744073709551615
  9. c64_2: FFFFFFFFFFFFFFFF - 18446744073709551615
  10. c64_3: FFFFFFFFFFFFFFFF - 18446744073709551615
  11. v64  : FFFFFFFFFFFFFFFF - 18446744073709551615
  12.  


Remy Lebeau

  • Hero Member
  • *****
  • Posts: 813
    • Lebeau Software
Re: Implicit converison, literals and QWORD variable warning
« Reply #1 on: August 06, 2020, 06:17:29 pm »
(posting a new thread since the original thread is locked)

The Rio is the current version of Delphi, AFAIK

Actually, 10.4 Sydney was released a few months ago.  10.3 Rio was the previous version, released in late 2018.

Can anyone who have Rio confirm all this?

I have posted the question to the Delphi forum:

FreePascal compatibility - how is this kind of code compiled in Delphi 10.3 Rio or 10.4 Sydney?
« Last Edit: August 06, 2020, 06:24:18 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

Thaddy

  • Hero Member
  • *****
  • Posts: 10462
Re: Implicit converison, literals and QWORD variable warning
« Reply #2 on: August 06, 2020, 06:24:46 pm »
Interesting.
As I wrote before, how can the compiler know if a certain bit pattern is to be interpreted as signed or unsigned given an untyped const?
I don't believe Delphi 10.4 can do that, unless on use and with type inference, which would be BAD. Somebody is plain lying here....
On the CPU level this is impossible. It is either signed or unsigned.
Whereas a typed const has the required capability.
« Last Edit: August 06, 2020, 06:34:12 pm by Thaddy »
When you ask a question that is actually answered in the documentation, you are either lazy or a moron.

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8727
  • FPC developer.
Re: Implicit converison, literals and QWORD variable warning
« Reply #3 on: August 06, 2020, 06:59:17 pm »
(I merged some follow ups to the locked thread (I don't know who locked it).

Julkas: read the thread referenced in the url in Remy's post.

Remy: thanks. Discovery is the key. Test both 32-bit and 64-bit.

FPK

  • Jr. Member
  • **
  • Posts: 83
Re: Implicit converison, literals and QWORD variable warning
« Reply #4 on: August 06, 2020, 07:21:13 pm »
The question is simple: is $FFFFFFFFFFFFFFFF a valid int64 or not? For FPC we decided, yes. For Delphi apparently not, at least not after when they introduced the 64 bit unsigned type.

julkas

  • Guest
Re: Implicit converison, literals and QWORD variable warning
« Reply #5 on: August 06, 2020, 07:34:40 pm »
Output on WSL -
Code: Bash  [Select][+][-]
  1. $ fpc -B consta.pas
  2. Free Pascal Compiler version 3.2.0 [2020/06/14] for x86_64
  3. Copyright (c) 1993-2020 by Florian Klaempfl and others
  4. Target OS: Linux for x86-64
  5. Compiling consta.pas
  6. consta.pas(10,36) Warning: range check error while evaluating constants (-1 must be between 0 and 18446744073709551615)
  7. consta.pas(13,22) Warning: range check error while evaluating constants (-1 must be between 0 and 18446744073709551615)
  8. consta.pas(21,5) Warning: unreachable code
  9. consta.pas(23,12) Warning: Comparison might be always false due to range of constant and expression
  10. consta.pas(24,5) Warning: unreachable code
  11. consta.pas(27,10) Warning: Comparison might be always false due to range of constant and expression
  12. consta.pas(28,5) Warning: unreachable code
  13. Linking consta
  14. 29 lines compiled, 1.5 sec
  15. 7 warning(s) issued
  16.  
  17. $ ./consta
  18. c64_1: FFFFFFFF - 4294967295
  19. c64_1 < 0
  20. c64_2: FFFFFFFFFFFFFFFF - 18446744073709551615
  21. c64_3: FFFFFFFFFFFFFFFF - 18446744073709551615
  22. v64  : FFFFFFFFFFFFFFFF - 18446744073709551615
  23.  

ASerge

  • Hero Member
  • *****
  • Posts: 1671
Re: Implicit converison, literals and QWORD variable warning
« Reply #6 on: August 06, 2020, 09:05:48 pm »
As I wrote before, how can the compiler know if a certain bit pattern is to be interpreted as signed or unsigned given an untyped const?
I don't believe Delphi 10.4 can do that, unless on use and with type inference, which would be BAD. Somebody is plain lying here....
Easy. Tries to use a single-byte signed type that includes the value of a constant. If not, a single-byte unsigned type. If it doesn't work, then a two-byte signed type, and so on.
Example:
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2. {$MODE OBJFPC}
  3.  
  4. procedure PrintTypeForNumber(const S: AnsiString);
  5. type
  6.   TRange = record
  7.     Min, Max: Int64;
  8.     TypeName: AnsiString;
  9.   end;
  10. const
  11.   CRanges: array[0..5] of TRange = (
  12.     (Min: Low(Int8); Max: High(Int8); TypeName: 'ShortInt'),
  13.     (Min: Low(UInt8); Max: High(UInt8); TypeName: 'Byte'),
  14.     (Min: Low(Int16); Max: High(Int16); TypeName: 'SmallInt'),
  15.     (Min: Low(UInt16); Max: High(UInt16); TypeName: 'Word'),
  16.     (Min: Low(Int32); Max: High(Int32); TypeName: 'Integer'),
  17.     (Min: Low(UInt32); Max: High(UInt32); TypeName: 'Cardinal'));
  18. var
  19.   RInt64: Int64;
  20.   RQWord: QWord;
  21.   Err: Integer;
  22.   iRange: TRange;
  23. begin
  24.   Val(S, RQWord, Err);
  25.   if (Err = 0) and (RQWord > High(Int64)) then
  26.   begin
  27.     Writeln(S, ' is QWord type');
  28.     Exit;
  29.   end;
  30.   Val(S, RInt64, Err);
  31.   if Err <> 0 then
  32.   begin
  33.     Writeln(S, ' is not integer value');
  34.     Exit;
  35.   end;
  36.   for iRange in CRanges do
  37.     if (RInt64 >= iRange.Min) and (RInt64 <= iRange.Max) then
  38.     begin
  39.       Writeln(S, ' is ', iRange.TypeName, ' type');
  40.       Exit;
  41.     end;
  42.   Writeln(S, ' is Int64 type');
  43. end;
  44.  
  45. var
  46.   S: AnsiString;
  47. begin
  48.   repeat
  49.     Write('Enter integer number (empty for exit):');
  50.     Readln(S);
  51.     if S = '' then
  52.       Break;
  53.     PrintTypeForNumber(S);
  54.   until False;
  55. end.
« Last Edit: August 06, 2020, 10:08:41 pm by ASerge »

julkas

  • Guest
Re: Implicit converison, literals and QWORD variable warning
« Reply #7 on: August 07, 2020, 08:10:16 am »
About C++ integer literals - https://en.cppreference.com/w/cpp/language/integer_literal
From Notes -
There are no negative integer constants.
« Last Edit: August 07, 2020, 08:17:52 am by julkas »

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8727
  • FPC developer.
Re: Implicit converison, literals and QWORD variable warning
« Reply #8 on: August 07, 2020, 10:07:40 am »
About C++ integer literals - https://en.cppreference.com/w/cpp/language/integer_literal
From Notes -
There are no negative integer constants.

No suffix means signed. Since we have no suffix at all, we are in compliance  O:-)

Seriously, the qword(literal value) on the rhs is probably equivalent to C++'s suffixes.

process_1

  • Guest
Re: Implicit converison, literals and QWORD variable warning
« Reply #9 on: August 07, 2020, 11:12:22 am »
No suffix means signed. Since we have no suffix at all, we are in compliance  O:-)

Seriously, the qword(literal value) on the rhs is probably equivalent to C++'s suffixes.

What julkas mentioned means exactly that - suffixes for integer literals are ignored in C++, they are always positive numbers. For negative numbers, negative sign is used. In C/C++ suffixes for hex numbers are L, LL, UL, ULL, but as wrote already, they are ignored in C++. Execute following code and you will see exact result of it:

Code: C  [Select][+][-]
  1.  
  2. #include <iostream>
  3.  
  4. using namespace std;
  5.  
  6. int main ()
  7. {
  8.   if (0xFFFFFFFFFFFFFFFF < 0)
  9.     cout << "0xFFFFFFFFFFFFFFFF is less than 0!\n";
  10.   else
  11.     cout << "0xFFFFFFFFFFFFFFFF is unsigned!\n";        // Always executable
  12.  
  13.  
  14.   if (0xFFFFFFFFFFFFFFFFLL < 0)
  15.     cout << "0xFFFFFFFFFFFFFFFFLL is less than 0!\n";
  16.   else
  17.     cout << "0xFFFFFFFFFFFFFFFFLL is unsigned!\n";      // Always executable
  18.  
  19.  
  20.   if (0xFFFFFFFFFFFFFFFFULL < 0)
  21.     cout << "0xFFFFFFFFFFFFFFFFULL is less than 0!\n";
  22.   else
  23.     cout << "0xFFFFFFFFFFFFFFFFULL is unsigned!\n";     // Always executable
  24.  
  25.   if (0xFFFFL < 0)
  26.     cout << "0xFFFFFL is less than 0!\n";
  27.   else
  28.     cout << "0xFFFFFL is unsigned!\n";  // Always executable
  29.  
  30.   return 0;
  31. }
  32.  

If you do not have any C++ compiler, there is online compiler, then choose any listed C++ standard of interest:

https://www.onlinegdb.com/online_c++_compiler
« Last Edit: August 07, 2020, 11:38:23 am by process_1 »

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8727
  • FPC developer.
Re: Implicit converison, literals and QWORD variable warning
« Reply #10 on: August 07, 2020, 11:44:48 am »
No suffix means signed. Since we have no suffix at all, we are in compliance  O:-)

Seriously, the qword(literal value) on the rhs is probably equivalent to C++'s suffixes.

What julkas mentioned means exactly that - suffixes for integers are ignored in C++, they are always positive numbers. For negative numbers, negative sign is used.

Ok, I read better, and it say a negative literal generates a unsigned value +  an unary minus operation. But how do you generate an operation for a constant? And what type does the constant have? It might be C/C++ substitution based parsing, trying to process that unary operation at every place the literal is used. I'm not sure Pascal works that way.

Moreover, as soon as you have binary operands, type promotion rules come out to play  then it is not just the literal definition, but the whole evaluation on the place it is used.

p.s. As I said before: if you want to make a standards argument, you must base it purely on the text. Testing with a compiler clouds the issue with potentially implementation defined behaviour.

process_1

  • Guest
Re: Implicit converison, literals and QWORD variable warning
« Reply #11 on: August 07, 2020, 12:10:32 pm »

Ok, I read better, and it say a negative literal generates a unsigned value +  an unary minus operation. But how do you generate an operation for a constant? And what type does the constant have? It might be C/C++ substitution based parsing, trying to process that unary operation at every place the literal is used. I'm not sure Pascal works that way.

Moreover, as soon as you have binary operands, type promotion rules come out to play  then it is not just the literal definition, but the whole evaluation on the place it is used.

Just post an example what you want to accomplish. Type promotion rules applies here without an issue.

Problem in FPC, however, is arbitrary rule for unwanted integer literals implicit conversion, as already pointed.

Quote
p.s. As I said before: if you want to make a standards argument, you must base it purely on the text. Testing with a compiler clouds the issue with potentially implementation defined behaviour.

All papers for C++ standards are here https://isocpp.org
For instance, C++20 standard is here: https://isocpp.org/files/papers/N4860.pdf

GNU C/C++ have to follow all these rules for specific standard, before they claims it is fully supported, is it?
« Last Edit: August 07, 2020, 12:25:36 pm by process_1 »

Warfley

  • Sr. Member
  • ****
  • Posts: 303
Re: Implicit converison, literals and QWORD variable warning
« Reply #12 on: August 07, 2020, 01:19:07 pm »
What julkas mentioned means exactly that - suffixes for integer literals are ignored in C++, they are always positive numbers. For negative numbers, negative sign is used. In C/C++ suffixes for hex numbers are L, LL, UL, ULL, but as wrote already, they are ignored in C++. Execute following code and you will see exact result of it:

This behaviour also is the only one that makes sense, because neither C nor C++ (before c++20) defined how signed numbers are implemented, which means overflow is undefined behaviour. A hex constant is just another way of writing a number. So you give the compiler a huge positive number which can not be converted to a signed number, because this would require overflow to be defined.
Now the compiler looks at the if cases and sees a comparison between a positive number and 0, and this is a trivial tautology. A positive number is never smaller than 0. So the compiler simply removes the if's completely, which can be seen when decompiling your project again:
Code: C  [Select][+][-]
  1. undefined8 main(void)
  2. {
  3.   operator<<<std--char_traits<char>>
  4.             ((basic_ostream *)__TMC_END__,"0xFFFFFFFFFFFFFFFF is unsigned!\n");
  5.   operator<<<std--char_traits<char>>
  6.             ((basic_ostream *)__TMC_END__,"0xFFFFFFFFFFFFFFFFLL is unsigned!\n");
  7.   operator<<<std--char_traits<char>>
  8.             ((basic_ostream *)__TMC_END__,"0xFFFFFFFFFFFFFFFFULL is unsigned!\n");
  9.   operator<<<std--char_traits<char>>((basic_ostream *)__TMC_END__,"0xFFFFFL is unsigned!\n");
  10.   return 0;
  11. }

You simply can't use positive numbers to represent negative numbers in C and C++ (at least until C++20). The correct and portable (between any size and signedness) way to have a bitmask where every bit is 1 is to write ~0

Note that also bitshifts which cross the negative positive boundary are undefined behaviour:
Code: C  [Select][+][-]
  1. int x = 1;
  2. x << 31; // undefined behaviour because the resulting number would be larger than 2^31-1
  3. x = -1;
  4. x >> 5; // undefined behaviour because right shift on negative number
  5.  

So writing large hex constants as bit masks for signed types, or shifting to the sign bit to create bit masks is simply broken C and C++ code

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 8727
  • FPC developer.
Re: Implicit converison, literals and QWORD variable warning
« Reply #13 on: August 07, 2020, 02:51:54 pm »
Just post an example what you want to accomplish. Type promotion rules applies here without an issue.

As said, literals are per definition signed. Even if you change the $FFFFFFFF etc to unsigned, then still the 0 is signed.

Quote
Problem in FPC, however, is arbitrary rule for unwanted integer literals implicit conversion, as already pointed.

Anything relating to the highest unsigned type is arbitrary, as I have explained it to be a hack since there is no larger signed type for it. But solutions must be limited to the place where the literal is parsed, and not fan out to every place where a literal might be used to try to preserve the expression as unsigned.

That is not fixing a corner case, but changing the language so far that it might as well be a new one.

And that brings us back to how Delphi does it. All this talk about C/C++ is utterly useless.

Quote
p.s. As I said before: if you want to make a standards argument, you must base it purely on the text. Testing with a compiler clouds the issue with potentially implementation defined behaviour.

All papers for C++ standards are here https://isocpp.org
For instance, C++20 standard is here: https://isocpp.org/files/papers/N4860.pdf

GNU C/C++ have to follow all these rules for specific standard, before they claims it is fully supported, is it?
[/quote]

They are like minimal rules. But not all behaviour that you see might be required, that 's what "implementation defined" means (and IIRC that is a term from K&R). See e.g. https://en.wikipedia.org/wiki/Unspecified_behavior

IOW two different C compilers might react different, but still be standards compliant. Therefore you can't advocate as anything GCC does as "the will of the standard". It might be one choice of many in the optional parts of the standard.

process_1

  • Guest
Re: Implicit converison, literals and QWORD variable warning
« Reply #14 on: August 07, 2020, 03:12:31 pm »
All this talk about C/C++ is utterly useless.

No body force you to read, nor to reply.

The benefit reading other standards is to learn how properly to handle problems in any compiler, not to reinvent the wheel. But even to reinvent wheel properly, it seems some Pandora's boxes are opened in the core of FPC. In this case consistency. But you constantly ignoring that, which is your problem and I do not really care about.

 

TinyPortal © 2005-2018