View Issue Details

IDProjectCategoryView StatusLast Update
0034864FPCDocumentationpublic2019-01-20 09:57
Reporteruser5570Assigned ToMichael Van Canneyt 
Status resolvedResolutionfixed 
PlatformLinux 64-bitOSUbuntuOS Version18.10
Product Version3.0.4Product Build 
Target Version3.2.0Fixed in Version3.3.1 
Summary0034864: Unexpected warning for declaration of QWORD constants
DescriptionFollowing returns warning without reason, even constant is explicitly defined as QWORD, evem result is wrote correctly (3.0.4 [2018/10/29] for x86_64).

program test;
  writeln (t);

With implicit cast, the warning vanishing: var t: QWORD = QWORD($FFFFFFFFFFFFFFFF)

I believe implicit definition is enough and the same as implicit cast. then warning is not necessary. As without any definition of QWORD, by default on 64-bit system, default is int64 (i.e. -1), as should be.

TagsNo tags attached.
Fixed in Revision
Attached Files


duplicate of 0021284 resolvedJonas Maebe FPC QWord $FFFF FFFF FFFF FFFF throws a range check error 
duplicate of 0001539 closedDarius Blaszijk Lazarus Code explorer duplicates entries 
has duplicate 0035176 resolvedJonas Maebe FPC false range check warning on large UInt64 constants 


Jonas Maebe

2019-01-13 13:03

manager   ~0113376

> With implicit cast, the warning vanishing: var t: QWORD = QWORD($FFFFFFFFFFFFFFFF)

This is an explicit cast. It is indeed the correct way to specify the type of the constant.


2019-01-13 14:44


Last edited: 2019-01-13 14:56

View 5 revisions

I meant implicit declaration (I was unable to edit description):


This make no warning.

Explicit declaration is this: const QWORD t = $FFFFFFFFFFFFFFFF;

And this kind of delaration have no much sense: const QWORD t = QWORD($FFFFFFFFFFFFFFFF);

By explicit declaration, destination It already know, in which case any warning with in specified range of 0..2^64-1 "tutoring" to programmer that should be in range of int64 is pointless, as unsigned 64 is exactly what is requested.

Further, by implicit cast, source range is specified, then as well destination - no warning to explicitly declare it, which is correct.

in other way, result is the same (correct) requested unsigned value. However, forcing warning make no sense at all with explicit declaration.

I do not have Delphi for 64-bit, however according to , range checking is full 64-bit range, which should mean that it should not complain in similar explicit declaration. As well, I do not use delphi mode directive with FPC/Lazarus new projects...

Making explicit and implicit cast in the same time (const QWORD t = QWORD($FFFFFFFFFFFFFFFF)) is unreadable and even worst with constants in array of multiple (100s) of individual constants (for instance, when implementing CORDIC with embedded hardware).

In C++ that is even more clear - no need to implicitly cast constants. In older C versions (I do not use quite a bit of C anymore), I believe it was necessary (adding ul or similar as well)...

However, it is long time passed and many revisions of C/C++ was changed, I see no point why Pascal should suffer for old definition. I also see now there is many the same requirements here.

In anyway, disabling range check errors may be bad practice otherwise when mixing unsigned and signed constants in order to avoid current behavior for declaration of unsigned 64-bit constants.

Please reconsider at least all upper, before reject.

Jonas Maebe

2019-01-13 15:43

manager   ~0113378

Pascal parses expressions context-insensitive (as much as possible). This means that when $FFFFFFFFFFFFFFFF, the compiler has no idea what will be done with it. Therefore, it has to decide what type this constant has merely based on its value. There are two choices: interpret it as an int64, or as a qword. The compiler uses int64, because Pascal generally uses the largest signed type to evaluate integer expressions.

Once it gets to the point where that constant gets assigned to a typed constant of the type qword, the compiler no longer knows this constant was specified as $FFFFFFFFFFFFFFFF, -1, int64(-1), or int64($FFFFFFFFFFFFFFFF). All it knows that there is a constant with the value -1 and the type int64. Hence, you get a warning, and hence you need to explicitly specify that the constant $FFFFFFFFFFFFFFFF needs to be interpreted as a qword.

Having the compiler automatically convert constants from signed to unsigned based on their use is the opposite of what Pascal stands for: do what the programmer writes, rather than do what the compiler thinks that the programmer meant.


2019-01-14 01:10


Last edited: 2019-01-14 01:15

View 3 revisions

Your explanation reveals exact issue with compiler, I believe need to be fixed.

I pointing here (as well as other people) inside declaration block, not literal values inside execution block. If type is already explicitly declared (as upper), there is all known in advance and double implicit conversion (compiler apparently forces, as you described) is not needed.

Since the resulting type is know already after parsing, it is quite logical to avoid unnecessary double conversion and in the same time, not at all wanted warning.

It is simply hard to believe that compiler is not capable to directly convert the literal with corespondent type inside definition block, but instead do virtual saving literal as the highest unsigned integer and then implicitly convert it back into already defined type, with a warning as a bonus...

That is all about the issue. Thank you for your explanation.

Serge Anvarov

2019-01-14 19:21

reporter   ~0113407

In FPC "All decimal constants which do no fit within the -2147483648..2147483647 range are silently and automatically parsed as 64-bit integer"
In Delphi the compiler tries to determine the constant type using different value ranges
As a result, Delphi has no warnings

Jonas Maebe

2019-01-14 23:20

manager   ~0113414

> I pointing here (as well as other people) inside declaration block, not literal values inside execution block.

There is no difference between the two. There is no reason why

  q: qword;

should behave differently from


or from

procedure test(q: qword);


All of those cases are exactly the same: converting the constant $FFFFFFFFFFFFFFFF to qword. Again: how something is used in Pascal is always irrelevant as to its interpretation. This makes code predictable, which is a good thing.

> In Delphi the compiler tries to determine the constant type using different value ranges

FPC does that too, although it indeed stops earlier than Delphi. FPC's documentation is also slightly outdated: $FFFFFFFF will be interpreted as high(cardinal). However, all hexadecimal numbers outside the range low(longint)..high(cardinal) will indeed be interpreted as int64 (which, FWIW, was Delphi-compatible until Delphi introduced a 64 bit unsigned integer type -- which FPC already supported for a very long time at that point).

Jonas Maebe

2019-01-14 23:21

manager   ~0113415

If you wish to continue this discussion, please do so on the fora or mailing lists. I will assign the bug report to Michael so he can update the documentation.


2019-01-15 06:28


Making any valid suggestion and applying any bug report is pointless here. It is obvious flaw in compiler's design and valid suggestion and pointed documentation for Delphi are obviously irrelevant here...

Stick with your flaws in design if you want, but do not thread reporters for ignorant - FPC is still far from perfection.

I have no intention to waste my time further on this.

Jonas Maebe

2019-01-15 09:25

manager   ~0113423

FPC is far from perfect and I don't think you are ignorant. There _are_ two choices:
* either $FFFFFFFFFFFFFFFF is always interpreted as high(qword), or
* $FFFFFFFFFFFFFFFF is always interpreted as int64(-1)

The main thing I was arguing against is interpreting it sometimes in one way and sometimes in the other, or in other words: interpreting it depending based on the context. That is something which will never be done (it would break the language at a fundamental level), and something that Delphi does not do either afaik.

We chose int64(-1) because that is what Delphi also did at the time, and also because of Pascal's tradition of not having an unsigned variant of the largest integer type (which means that in several cases there are trade-offs to be made between staying consistent with Pascal's "expected" way of working and extending it). Changing this is possible, but would break backward compatibility with existing code. This including potentially calling different overloads or evaluating mathematical expressions suddenly as unsigned instead of signed, which may result in very hard to find bugs.

It's almost never a matter of striving to be perfect. It's always a matter of navigating between not breaking people's existing code and potential improvements from changing things.

Michael Van Canneyt

2019-01-15 10:51

administrator   ~0113424


For the sake of Delphi compatibility, in Delphi mode the interpretion of $FFFFFFFFFFFFFFFF should probably be made Delphi compatible, and in that case a warning is not in order.

For objfpc we should of course for backwards compatibility stick to current behaviour.

Jonas Maebe

2019-01-15 22:10

manager   ~0113431

It depends on the version of Delphi we want to be compatible with in Delphi mode.


2019-01-16 16:39

reporter   ~0113440


if that was done, floating-point literals should be brought in line with Delphi too, otherwise it's going to cause even more confusion if some literals are interpreted mode-specific and some are not.

Michael Van Canneyt

2019-01-20 09:57

administrator   ~0113512

Documented type mapping mechanism after discussion with Jonas.

Issue History

Date Modified Username Field Change
2019-01-13 11:00 user5570 New Issue
2019-01-13 13:03 Jonas Maebe Note Added: 0113376
2019-01-13 13:03 Jonas Maebe Relationship added duplicate of 0021284
2019-01-13 13:03 Jonas Maebe Status new => resolved
2019-01-13 13:03 Jonas Maebe Resolution open => duplicate
2019-01-13 13:03 Jonas Maebe Assigned To => Jonas Maebe
2019-01-13 14:44 user5570 Note Added: 0113377
2019-01-13 14:44 user5570 Status resolved => feedback
2019-01-13 14:44 user5570 Resolution duplicate => reopened
2019-01-13 14:46 user5570 Note Edited: 0113377 View Revisions
2019-01-13 14:49 user5570 Note Edited: 0113377 View Revisions
2019-01-13 14:50 user5570 Note Edited: 0113377 View Revisions
2019-01-13 14:56 user5570 Note Edited: 0113377 View Revisions
2019-01-13 15:43 Jonas Maebe Note Added: 0113378
2019-01-13 15:43 Jonas Maebe Status feedback => resolved
2019-01-13 15:43 Jonas Maebe Resolution reopened => duplicate
2019-01-14 01:10 user5570 Note Added: 0113389
2019-01-14 01:10 user5570 Status resolved => feedback
2019-01-14 01:10 user5570 Resolution duplicate => reopened
2019-01-14 01:13 user5570 Note Edited: 0113389 View Revisions
2019-01-14 01:15 user5570 Note Edited: 0113389 View Revisions
2019-01-14 19:21 Serge Anvarov Note Added: 0113407
2019-01-14 23:20 Jonas Maebe Note Added: 0113414
2019-01-14 23:21 Jonas Maebe Note Added: 0113415
2019-01-14 23:21 Jonas Maebe Assigned To Jonas Maebe => Michael Van Canneyt
2019-01-14 23:21 Jonas Maebe Status feedback => assigned
2019-01-14 23:21 Jonas Maebe Category Compiler => Documentation
2019-01-15 06:28 user5570 Note Added: 0113419
2019-01-15 09:25 Jonas Maebe Note Added: 0113423
2019-01-15 10:51 Michael Van Canneyt Note Added: 0113424
2019-01-15 22:10 Jonas Maebe Note Added: 0113431
2019-01-16 16:39 Martok Note Added: 0113440
2019-01-20 09:57 Michael Van Canneyt Note Added: 0113512
2019-01-20 09:57 Michael Van Canneyt Relationship added duplicate of 0001539
2019-01-20 09:57 Michael Van Canneyt Status assigned => resolved
2019-01-20 09:57 Michael Van Canneyt Fixed in Version => 3.3.1
2019-01-20 09:57 Michael Van Canneyt Resolution reopened => fixed
2019-01-20 09:57 Michael Van Canneyt Target Version => 3.2.0
2019-03-02 10:58 Jonas Maebe Relationship added has duplicate 0035176