View Issue Details

IDProjectCategoryView StatusLast Update
0024318FPCCompilerpublic2018-01-07 19:53
ReporterFeliks KluzniakAssigned ToJonas Maebe 
PrioritynormalSeveritymajorReproducibilityalways
Status resolvedResolutionfixed 
PlatformMacBook ProOSMac OS XOS Version10.8.3
Product Version2.6.0Product Build [2011/12/30] for i386 
Target VersionFixed in Version3.1.1 
Summary0024318: Bad code is generated for "for" clauses if range variables are involved.
DescriptionGiven variables "high", "low" and "ttop", all of the same integer range type, the loop beginning with

   "for high := low to ttop - 1 do"

iterates even when "low" is initially greater than "ttop - 1".

Looks as if unsigned arithmetic is used, incorrectly.

The same behaviour is observed in several modes: FPC, TP, ISO.
Steps To ReproduceSee the attached file. The body of the loop should not be entered at all, instead the iterations go on and on...

This is extracted from a larger program that was written in 1983 and ran with several implementations of the original "Wirth/Jensen" Pascal, then with Turbo Pascal and some others. With Free Pascal it fails.
TagsNo tags attached.
Fixed in Revision37934
FPCOldBugId
FPCTarget
Attached Files

Activities

Feliks Kluzniak

2013-04-24 18:50

reporter  

range.p (313 bytes)

Florian

2013-04-24 19:20

administrator   ~0067136

All compilers I tested (FPC, TP, GPC) give a range check error for the code if range checking is turned on so I suspect it just worked by accident.

Jonas Maebe

2013-04-25 10:20

manager   ~0067144

The behaviour of code that contains range errors is indeed undefined in FPC.

Feliks Kluzniak

2013-04-25 13:50

reporter   ~0067151

May I respectfully suggest that you have not given this issue sufficient attention? There is no range error here: none of the range variables is assigned a value out of range. (In the object code it may be assigned such a value as a result of overly simplistic translation, but that's not the programmer's problem.)

A range variable is just a normal integer, except that it shouldn't be assigned a value out of range. Comparison with a value that is out of range is quite legal. If your implementation treats the expression "0 <= -1" as true, then it is simply broken.

If the compilers you tested give range errors, then they are incorrect. I can assure you that in the days when we had many real implementations of Pascal this code worked correctly with all the possible checks turned on.

This is hardly an obscure corner of the language. Range types are quite natural to use for the indices of an array. If you implement, say, a stack in an array, then the idiom whose essence is used in the example is the obvious one for, say, printing out the contents of the stack.

Jonas Maebe

2013-04-25 14:24

manager   ~0067152

Last edited: 2013-04-25 23:27

View 2 revisions

From the ISO Extended Pascal standard document (http://www.standardpascal.org/iso10206.pdf ):

Point 6.9.3.9.2:
***
The initial-value and the final-value of a sequence-iteration of an iteration-clause of a for-statement shall be of a type compatible with the type of the control-variable of the for-statement. The initial-value and the final-value shall be assignment-compatible with the type possessed by the control-variable if the statement of the for-statement is executed.
***

The definition of "assignment-compatible" is (6.4.6):

***
A value of type T2 shall be designated assignment-compatible with a type T1 if any of the following
six statements is true:
a) T1 and T2 are the same type, and that type is permissible as the component-type of a le-type
(see 6.4.3.6).
NOTE | Because T1 and T2 are types, rather than type-denoters, the restriction on the bindability
of component-types of le-types does not apply here.
b) T1 is the real-type and T2 is the integer-type.
c) T1 is the complex-type and T2 is either the integer-type or the real-type.
d) T1 and T2 are compatible ordinal-types, and the value of type T2 is in the closed interval
specified by the type T1.
e) T1 and T2 are compatible set-types, and all the members of the value of type T2 are in the
closed interval speci ed by the base-type of T1.
f) T1 and T2 are compatible, T1 is a string-type or the char-type, and the length of the value of
T2 is less than or equal to the capacity of T1 (see 6.4.3.3).
***

Point d) applies here (ordinal types), and hence the final-value of the for-statement must be a valid value as far as the type of the control-variable is concerned.

Florian

2013-04-25 18:24

administrator   ~0067157

I think it becomes even more clear from the equivalent code sample given in the ext. pascal document which introduces temp1 and temp2 and which states below the code samples that temp1 and temp2 should have the same range type as the counter variable.

Feliks Kluzniak

2013-04-25 23:51

reporter   ~0067164

Thank you for the careful argument. However, I believe you have not interpreted the standard quite correctly, and here are my reasons.

As you quote: "The initial-value and the final-value shall be assignment-compatible with the type possessed by the control-variable ***if the statement of the for-statement is executed***." [stress added]

But this is exactly the point: in my example the statement of the for-statement should not be executed. So what applies here is the previous phrase: "shall be of a type compatible with the type of the control-variable". Compatible, not assignment-compatible.

Now, type compatibility is defined in Sec. 6.4.5: "Types T1 and T2 shall be designated compatible if ... (b) T1 and T2 are ordinal types and have the same range-type (see 6.4.2.1)."

So we look at 6.4.2.1: "The _range-type_ of an ordinal-type that is a subrange-type shall be the host-type (see 6.4.2.4) of the subrange-type."

So we look at 6.4.2.4: "The subrange-bounds shall be of compatible ordinal-types, and the range-type (see 6.4.2.1) of the ordinal-types shall be designated the _host-type_ of the subrange-type."

Notice that we are now interested in the range-type not of the subrange-type itself, but of the ordinal type(s) from which we have taken the bounds with which it was defined. In my example this is the integer type. (Different subrange types may have the same host type: the distinction here is between subranges of integers, subranges of char, subranges of some particular enumerated type.)

And indeed, in 6.4.2.1 we read: "the _range-type_ of an ordinal-type that is not a subrange-type shall be the ordinal-type."

This stands to reason. The host type of a range type such as "ttx = 0 .. 800" is the integer type and therefore type "ttx" is compatible with type "integer" (though not assignment-compatible). Therefore my example is legal: comparison with the final value _before_ entering the loop is a comparison between values of compatible types, and should fail.

So much for the standard. If you look at the example as programmers, you will see that it would be most unnatural if one were not able to write such a loop, and the fact that the loop does iterate cannot be called anything but highly surprising.

I submit that this is indeed an error in the compiler.

Jonas Maebe

2013-04-26 09:51

manager   ~0067167

The compatibility clause means that the compiler must not give a compile time error if your control-variable's type is 0..800, but the initial-value and/or final-value are e.g. of type integer.

The assignment of the initial-value to the control-variable and the check whether the control-variable is smaller than or equal to the final-value are part of the for-statement (there is no other statement these operations could be part of). The loop body is not the only part of the for-statement. The for-statement gets executed as soon as the control flow of the program reaches it, and as soon as that is the case all the "executed" conditions must be true for the code to be valid.

See also Florian's reference to the equivalent code for the for-statement in the standard document, which may make this even clearer.

Feliks Kluzniak

2013-04-26 19:24

reporter   ~0067177

Last edited: 2013-04-26 19:27

View 2 revisions

It is quite clear that the "statement of the for-statement" mentioned by 6.9.3.9.2 refers to the "statement" in the grammar rule of 6.9.3.9.1:

   for-statement = 'for' control-variable iteration-clause 'do' statement .

If this were not so, then the phrase "if the statement of the for-statement is executed" would make no sense.

As for the "equivalent code", it only supports my claim. The variables "temp1" and "temp2" are said to be of "the range-type of the type possessed by the variable v": in other words, not of the type of "v", but of the corresponding range-type, which is "integer", as I demonstrated in my last entry.

The compiler is incorrect.

Florian

2013-04-26 19:53

administrator   ~0067178

Even if this applies, for FPC, the range-type is not integer but an unsigned type because it knows unsigned host-types which is not part of the iso standard.

Maybe I just remove the iso switch again to avoid wasting my time with discussions about 30 years old code and compilers.

Maurice Lombardi

2013-04-27 13:58

reporter   ~0067181

The unsigned issue is not the point.
If ttlow is set to -1 to force range-type of ttx to integer,
and the for loop becomes
   for high := low to ttop - 2 do
the range check error is triggered
So high is enforced to be assignment compatible with the upper limit even if the for loop body is never entered.

Feliks Kluzniak

2013-04-28 00:11

reporter   ~0067196

Gentlemen, this is my last message on the subject.

One of you says: "to avoid wasting my time with discussions about 30 years old code and compilers".

I was labouring under the misapprehension that this project is about saving a beautiful language that is on the verge of dying out, and that people who attend to the error reports are actually interested both in Pascal and in compilers. My apologies for being mistaken.

The remark beginning with "The unsigned issue is not the point" is very hard to understand. If ttlow were set to -1, then of course it should trigger a range check error. The whole point is that it wasn't. And no, unsigned arithmetic does not enter the picture: not a part of the original Pascal, and --- as you mention --- not part of ISO.

So the conclusions are as follows:
 (1) The program is legal with respect to the ISO standard.
 (2) The behaviour of the generated code is very unexpected.
 (3) The compiler does not fully support subrange types.

All this does not seem to bother you. This is, of course, your privilege.

Thank you for the time spent on this. I wish you both a happy and fruitful life.

Jonas Maebe

2018-01-07 19:52

manager   ~0105462

Last edited: 2018-01-07 19:53

View 2 revisions

In ISO mode, the compiler now evaluates the lower and upper bound of the loop using the range-type as defined by the ISO standard.

Issue History

Date Modified Username Field Change
2013-04-24 18:50 Feliks Kluzniak New Issue
2013-04-24 18:50 Feliks Kluzniak File Added: range.p
2013-04-24 19:20 Florian Note Added: 0067136
2013-04-25 10:20 Jonas Maebe Note Added: 0067144
2013-04-25 10:20 Jonas Maebe Status new => resolved
2013-04-25 10:20 Jonas Maebe Resolution open => no change required
2013-04-25 10:20 Jonas Maebe Assigned To => Jonas Maebe
2013-04-25 13:50 Feliks Kluzniak Note Added: 0067151
2013-04-25 13:50 Feliks Kluzniak Status resolved => feedback
2013-04-25 13:50 Feliks Kluzniak Resolution no change required => reopened
2013-04-25 14:24 Jonas Maebe Note Added: 0067152
2013-04-25 14:24 Jonas Maebe Status feedback => resolved
2013-04-25 14:24 Jonas Maebe Resolution reopened => no change required
2013-04-25 18:24 Florian Note Added: 0067157
2013-04-25 23:27 Jonas Maebe Note Edited: 0067152 View Revisions
2013-04-25 23:51 Feliks Kluzniak Note Added: 0067164
2013-04-25 23:51 Feliks Kluzniak Status resolved => feedback
2013-04-25 23:51 Feliks Kluzniak Resolution no change required => reopened
2013-04-26 09:51 Jonas Maebe Note Added: 0067167
2013-04-26 09:51 Jonas Maebe Status feedback => resolved
2013-04-26 09:51 Jonas Maebe Resolution reopened => no change required
2013-04-26 19:24 Feliks Kluzniak Note Added: 0067177
2013-04-26 19:24 Feliks Kluzniak Status resolved => feedback
2013-04-26 19:24 Feliks Kluzniak Resolution no change required => reopened
2013-04-26 19:27 Feliks Kluzniak Note Edited: 0067177 View Revisions
2013-04-26 19:53 Florian Note Added: 0067178
2013-04-27 13:58 Maurice Lombardi Note Added: 0067181
2013-04-28 00:11 Feliks Kluzniak Note Added: 0067196
2013-04-28 00:11 Feliks Kluzniak Status feedback => assigned
2018-01-07 19:52 Jonas Maebe Fixed in Revision => 37934
2018-01-07 19:52 Jonas Maebe Note Added: 0105462
2018-01-07 19:52 Jonas Maebe Status assigned => resolved
2018-01-07 19:52 Jonas Maebe Fixed in Version => 3.1.1
2018-01-07 19:52 Jonas Maebe Resolution reopened => fixed
2018-01-07 19:53 Jonas Maebe Note Edited: 0105462 View Revisions