Public Comment Number PC-UK0268 ISO/IEC CD2 9899 (SC22N2794) Public Comment =========================================== Date: 1998-09-22 Author: N.M Maclaren Author Affiliation: Self Postal Address: University of Cambridge, Computer Laboratory, New Museums Site, Pembroke Street, Cambridge CB3 3QG, United Kingdom E-mail Address: Telephone Number: +44 1223 334761 Fax Number: +44 1223 334679 Category: Normative change to existing feature retaining the original intent Committee Draft subsection: 6.7.5.2 Title: Serious problems with side-effects in VLAs Detailed description: PC-UK0171 raised some very serious problems with ambiguities and traps for the programmer to do with the lack of specification of side effects in VLAs. Upon thinking the matter over further, the problem is even more serious than that comment indicated. Consider the following code: int fred (void) { int n = 0, m = INT_MAX; while (m > 0) {++n; m >>= 1;} return n; } ... double d[fred()]; In this context, does the call to the function fred result in undefined behaviour, the return of an unspecified value, or is it required to give the expected answer? Note that the way that the '++n;' passes its value to the 'return n;' is through the side effect of updating 'n' - and side effects need not take place during the execution of a VLA size expression. This situation is a recipe for chaos, and needs resolution. I suggest one of the following solutions: 1) To make it a constraint error to use a VLA size expression that has a side-effect or calls a function. This would permit almost all 'reasonable' uses, diagnose those that were invalid and give the implementor a very easy time. I doubt that most programmers would ever notice the restriction. 2) To define that side-effects occur as in ordinary expressions, except possibly in parameter declarations. Algol 68 and other languages have shown that this is technically simple, though existing compilers might need some reorganisation. There should be no need for incompatible changes to compiled code. After all, the compiler has to permit a function call, which can then do anything! The second was a major problem in CD1, because of the strange scope rules for VLA sizes, but is not a problem in CD2. If the sentence "It is unspecified whether side effects are produced when the size expression is evaluated." is removed from 6.7.5.2 paragraph 3, the following declaration: double fred[expr_1][expr_2], joe[expr_3][expr_4]; is effectively equivalent to the following code: int __hidden1, __hidden2, __hidden3, __hidden4; (void) ( (__hidden1 = (expr_1)) + (__hidden2 = (expr_2)) ); /* A */ (void) ( (__hidden3 = (expr_3)) + (__hidden4 = (expr_4)) ); /* B */ double fred[__hidden1][__hidden2], joe[__hidden3][__hidden4]; except for such details as the later visibility of the identifiers and any possible overflow during the additions. The sequence point defined in 6.7.5 paragraph 3 demands the separation of the two lines marked A and B, and the fact that there is no internal sequence point between the two sizes is clearly stated in D.3.2 paragraph 5. Incidentally, the above transformation is PRECISELY how compilers that support such facilities have always implemented them. These include Egtran, Algol 60, Algol 68 and Fortran 90. VLAs in parameter declarations are a bit nasty, largely because array types there are mapped into pointers. If solution (1) is adopted, there is clearly no problem. If solution (2) is adopted, the cleanest approach is to say that the sizes of such VLAs are not evaluated. This is similar to the specification of sizeof for non-VLA types, and helps to keep it clear that VLA parameters are really pointers. I have not included wording, but I believe that Clive Feather has offered to do so.