ISO/ IEC JTC1/SC22/WG14 N683


    WG14/N683 (J11/97-046)               WG14/N683 (J11/97-046)

              Final Edits for incorporating VLAs into C9X

                           Tom MacDonald
                           [email protected]

                           655F Lone Oak Road
                           Eagan  MN  55121
                           USA

                           08-May-1997



The following edits are against version C9XD9-pre3.

Quoted text (e.g., "sizeof") implies bold-courier font.


%%
%% Change #1
%%

        6.1.2.4 Storage duration of objects

	[#3] An object whose identifier is declared with no linkage
	and without the storage-class specifier static has automatic
	storage duration.  Storage is guaranteed to be reserved for
	a new instance of such an object on each normal entry into
	the block with which it is associated

End the sentence in C9XD9-pre3 here, and replace its final clause:

						, or on a jump from
	outside the block to a labeled statement in the block or in
	an enclosed block.

With:

						.  If the block with
	which the object is associated is entered by a jump from
	outside the block to a labeled statement in the block or in
	an enclosed block, then storage is guaranteed to be reserved
	provided the object does not have a variable length array
	type.  If the object is variably modified and the block is
	entered by a jump to a labeled statement, then the behavior
	is undefined.

End of change.



%%
%% Change #2
%%

Add the following forward references to 6.1.2.4

	variably modified (6.5.4), variable length array (6.5.4.2).

End of change.



%%
%% Change #3
%%

	6.1.2.6 Compatible type and composite type

	[#3] A composite type can be constructed from two types that
	are compatible; it is a type that is compatible with both of
	the two types and satisfies the following conditions:

Replace the following words in C9XD9-pre3:

	    - If one type is an array of known size, the composite
	      type is an array of that size.

With:

	- If one type is an array of known constant size, the
	  composite type is an array of that size; otherwise, if one
	  type is a variable length array the composite type is that
	  type.

End of change.



%%
%% Change #4
%%

	6.3 Expressions

	6.3.3.4 The "sizeof" operator

	Semantics

	[#2] The "sizeof" operator yields the size (in bytes) of its
	operand, which may be an expression or the parenthesized
	name of a type.

Replace the following words in C9XD9-pre3:

			The size is determined from the type of the
	operand, which is not itself evaluated.  The result is an
	integer constant.

With:

	The size is determined from the type of the operand.
	The result is an integer.  If the type of the operand
	is a variable length array type, the operand is evaluated;
	otherwise, the operand is not evaluated and the result is
	an integer constant.

End of change.



%%
%% Change #5
%%

Add the following example to 6.3.3.4:

	int fsize3(int n) {
	   char b[n+3];         /* variable length array     */
	   return sizeof b;     /* execution time sizeof     */
	}

	main() {
           int size;
	   size = fsize3(10);   /* func returns the value 13 */
	}

End of change.



%%
%% Change #6
%%

Add the following forward reference to 6.3.3.4

	variable length array (6.5.4.2).

End of change.



%%
%% Change #7
%%

Add the following example to 6.3.6 Additive operators:

	Pointer arithmetic is well defined with pointers to
	variable length array types.

        {
           int n = 4, m = 3;
           int a[n][m];
           int (*p)[m] = a;   /* p == &a[0]    */
           p += 1;            /* p == &a[1]    */
           (*p)[2] = 99;      /* a[1][2] == 99 */
           n = p - a;         /* n == 1        */
        }

	If array "a" in the above example is declared to be an
	array of known constant size, and pointer "p" is declared
	to be a pointer to an array of the same known constant
	size that points to "a", the results are still the same.

End of change.



%%
%% Change #8
%%

	6.4 Constant expressions

	[#6] An integral constant expression shall have integral
	type and shall only have operands that are integer
	constants, enumeration constants, character constants,
	"sizeof" expressions

Add the following words to paragraph 6 above:

			whose operand does not have variable
	length array type or a parenthesized name of such a type,


End of change.



%%
%% Change #9
%%

Add the following forward reference to 6.4

	variable length array (6.5.4.2).

End of change.



%%
%% Change #10
%%

	6.5 Declarations

	6.5.2 Type specifiers

Add the following as a new paragraph to the end of the Constraints:

	Only ordinary identifiers (as defined in 6.1.2.3) with
	block scope or function prototype scope and without linkage
	can have a variably modified type.  If an identifier is
	declared to be an object with static storage duration, it
	shall not have a variable length array type.

End of change.



%%
%% Change #11
%%

Add the following example to 6.5.2 Type specifiers:

	All declarations of variably modified (VM) types must be declared at
	either block scope or function prototype scope.  Array objects
	declared with the "static" or "extern" storage class specifier cannot
	have a variable length array (VLA) type.  However, a object declared
	with the "static" storage class specifier can have a VM type (that
	is, a pointer to a VLA type).  Finally, all identifiers declared
	with a VM type must be ordinary identifiers, and can not, therefore,
	be members of structures or unions.

	extern int n;
	int A[n];                       /* Error - file scope VLA */
	extern int (*p2)[n];            /* Error - file scope VM */
	int B[100];                     /* OK - file scope but not VM */

	void fvla(int m, int C[m][m]) { /* OK - VLA with prototype scope */
	   typedef int VLA[m][m];       /* OK - block scope typedef VLA */
					/* array size m evaluated now */
	   struct tag {
	      int (*y)[n];       /* Error - y is not an ordinary identifier */
	      int z[n];          /* Error - z is not an ordinary identifier */
	   };
	   int D[m];                    /* OK - auto VLA */
	   static int E[m];             /* Error - static block scope VLA */
	   extern int F[m];             /* Error - F has linkage and is a VLA */
	   int (*s)[m];                 /* OK - auto pointer to VLA */
	   extern int (*r)[m]; /*Error - r has linkage and is a pointer to VLA*/
	   static int (*q)[m] = &B; /* OK - q is a static block scope VM */

           /* ... */

	}

End of change.



%%
%% Change #12
%%

Add the following forward references to 6.5.2

	variably modified (6.5.4), variable length array (6.5.4.2).

End of change.


%%
%% Change #13
%%

	6.5.2.1 Structure and union specifiers

	[#7] A member of a structure or union may have any object type

Add the following words to paragraph 7 above:

	other than a variably modified type. *Footnote
____________________

	* A structure or union can not contain a member with a
	  variably modified type bacause member names are not ordinary
	  identifiers as defined in 6.1.2.3

End of change.



%%
%% Change #14
%%

	6.5.4 Declarators

	[#2] Each declarator declares one identifier, and asserts
	that when an operand of the same form as the declarator
	appears in an expression, it designates a function or object
	with the scope, storage duration, and type indicated by the
	declaration specifiers.

Add the following paragraph after paragraph 2 above:

	A `full declarator' is a declarator that is not part of
	another declarator.  The end of a full declarator is a
	sequence point.  If the nested sequence of declarators in a
	full declarator contains a variable length array type, the
	type specified by the full declarator is said to be "variably
	modified."

End of change.



%%
%% Change #15
%%

Add the following forward reference to 6.5.4

	variable length array (6.5.4.2).

End of change.


%%
%% Change 16
%%

	6.5.4.2 Array Declarators

	Constraints

Replace the following words in C9XD9-pre3:

	[#1] The expression delimited by [ and ] (which specifies
	the size of an array) shall be an integral constant
	expression that has a value greater than zero.

With:

	The [ and ] may delimit an expression or *.  If [ and ]
	delimit an expression (which specifies the size of an
	array), it shall have an integral type.  If the expression
	is a constant expression then it shall have a value greater
	than zero.

End of change.



%%
%% Change 17
%%

	Semantics

	[#2] If, in the declaration ``T D1,'' D1 has the form

Replace the following words in C9XD9-pre3:

		D[ constant-expr   ]
				opt

With:

		D[ assignment-expression   ]
					opt

			or

		D[*]

End of change.



%%
%% Change 18
%%

	and the type specified for ident in the declaration ``T D''
	is ``derived-declarator-type-list T,'' then the type
	specified for ident is ``derived-declarator-type-list array
	of T.''  If the size is not present, the array type is an
	incomplete type.

Add the following words to paragraph 2 above:

				If * is used instead of a size
	expression, the array type is a variable length array type
	of unspecified size, which can only be used in declarations
	with function prototype scope.  If the size expression is an
	integer constant expression and the element type has a known
	constant size, the array type is not a variable length array
	type.  Otherwise, the array type is a variable length array
	type.   If the size expression is not a constant expression,
	and it is evaluated at program execution time, it shall
	evaluate to a value greater than zero.  It is unspecified
	whether side effects are produced when the size expression is
	evaluated.  The size of each instance of a variable length
	array type does not change during its lifetime.

End of change.



%%
%% Change 19
%%

	[#3] For two array types to be compatible, both shall have
	compatible element types, and if both size specifiers are
	present

Replace the following words in C9XD9-pre3:

		they shall have the same value.

With:

		and integer constant expressions, then both size
	specifiers shall have the same constant value.  If the two
	array types are used in a context which requires them to be
	compatible, it is undefined behavior if the two size
	specifiers evaluate to unequal values.

End of change.



%%
%% Change 20
%%

Add the following as example 3 to 6.5.4.2 Array declarators:

	extern int n;
	extern int m;

	fcompat() {
	   int a[n][6][m];
	   int (*p)[4][n+1];
	   int c[n][n][6][m];
	   int (*r)[n][n][n+1];
	   p = a; /* Error - not compatible because 4 != 6                    */
	   r = c; /* compatible, but defined behavior only if n==6 and m==n+1 */
	}

End of change.



%%
%% Change 21
%%

	6.5.4.3 Function declarators (including prototypes)

	[#5] A parameter type list specifies the types of, and may
	declare identifiers for, the parameters of the function.

Add the following words to paragraph 5 above:

	A declared parameter that is a member of the parameter type
	list that is not part of a function definition, may use the
	[*] notation in its sequence of declarator specifiers to
	specify a variable length array type.

End of change.



%%
%% Change 22
%%

Add the following as examples 4 and 5 to 6.5.4.3 Function declarators:

    4.  The following prototype has a variably modified parameter.

	void addscalar(int n, int m, double a[n][n*m+300], double x);

	main() {
	   double b[4][308];
	   addscalar(4, 2, b, 2.17);
	}

	void addscalar(int n, int m, double a[n][n*m+300], double x) {
	   int i, j, k=n*m+300;

	   for (i = 0; i < n; i++)
	      for (j = 0; j < k; j++)
		 a[i][j] += x;    /* a is a pointer to a VLA with
                                     n*m+300 elements                */
	}


    5.  The following are all compatible function prototype declarators.

	double maximum(int n, int m, double a[n][m]);
	double maximum(int n, int m, double a[*][*]);
	double maximum(int n, int m, double a[ ][*]);
	double maximum(int n, int m, double a[ ][m]);

End of change.



%%
%% Change 23
%%

	6.5.6 Type definitions

Add the following Constraint to 6.5.6 Type definitions:

	Constraints:

	If a typedef name specifies a variably modified type
	then it shall have block scope.

End of change.



%%
%% Change 24
%%

	[#2] In a declaration whose storage-class specifier is
	typedef, each declarator defines an identifier to be a
	typedef name that specifies the type specified for the
	identifier in the way described in 6.5.4.

Add the following words to paragraph 2 above:

						Any array size
	expressions associated with variable length array
	declarators shall be evaluated with the typedef name at the
	beginning of its scope upon each normal entry to the block.

End of change.



%%
%% Change 25
%%

Add the following as examples 5 and 6 to 6.5.6 Type definitions:

    5  The following is a block scope declaration of a typedef name "A"
       with a variable length array type.

	void tdef(int n) {
	   typedef int A[n];   /* OK - declared with block scope */
	   A a;
	   A *p;
	   p = &a;
	}

    6. The size expression that is part of the variable length array type
       named by typedef name "B" is evaluated each time function "copyt" is
       entered.  However, the size of the variable length array type
       does not change if the value of "n" is subsequently changed.

        void copyt(int n) {
           typedef int B[n]; /* B is n ints with n evaluated now */
           n += 1;
           {
              B a;           /* a is n ints - n without += 1 */
              int b[n];      /* a and b are different sizes */
              for (i = 1; i < n; i++)
                 a[i-1] = b[i];
           }
        }

End of change.



%%
%% Change 26
%%

	6.5.7 Initialization

Replace the following words in C9XD9-pre3:

	[#3] The type of the entity to be initialized shall be an
	object type or an array of unknown size.

With:

	The type of the entity to be initialized shall be an
	object type that is not a variable length array type,
	or an array of unknown size.

End of change.



%%
%% Change 27
%%

6.6.2 Compound statement, or block

	[#2] A compound statement (also called a block) allows a set
	of statements to be grouped into one syntactic unit, which
	may have its own set of declarations and initializations (as
	discussed in 6.1.2.4).  The initializers of objects that
	have automatic storage duration

Add the following words to paragraph 2 above:

					, and the variable length
	array declarators of ordinary identifiers with block scope
	.......

End of change.



%%
%% Change 28
%%

	6.6.4.2 The "switch" statement

	[#1] The controlling expression of a "switch" statement shall
	have integral type

Add the following words to paragraph 1 above:

				, and shall not cause a block to
	be entered by a jump from outside the block to a statement
	that follows a case or default label in the block (or an
	enclosed block) if that block contains the declaration of a
	variably modified object or variably modified typedef name.

End of change.



%%
%% Change 29
%%

There is no change 29.  There used to be a change 29, but after reading
editorial review committee comments, I decided the proposed example was
unnecessary.  However, I didn't want to renumber the remaining changes.

End of change.



%%
%% Change 30
%%

	6.6.6.1 The goto statement

Add the following constraint as the second sentence to the Constraints of
6.6.6.1 The goto statement:

	A "goto" statement shall not cause a block to be entered by
	a jump from outside the block to a labeled statement in
	the block (or an enclosed block) if that block contains
	the declaration of a variably modified object or
	variably modified typedef name

End of change.



%%
%% Change 31
%%

Add the following example as the second example to 6.6.6.1 The goto statement:


    2.  A "goto" statment is not allowed to jump past any
        declarations of objects with variably modified types.
        A jump within the block, however, is permitted.

	goto lab3;  /* Error - going INTO scope of variable length array */
	{
	   double a[n];
	   a[j] = 4.4;
	lab3:
	   a[j] = 3.3;
	   goto lab4; /* OK - going WITHIN scope of variable length array */
	   a[j] = 5.5;
	lab4:
	   a[j] = 6.6;
	}
	goto lab4; /* Error - going INTO scope of variable length array */

End of change.



%%
%% Change 32
%%

	6.7.1 Function definitions

	[#9] On entry to the function

Add the following words to paragraph 9 above:

					all size expressions of its
	variably modified parameters are evaluated, and
	.....

End of change.



%%
%% Change 33
%%

7.6.2.1 The longjmp function

Add the following example to the longjmp function:

	The "longjmp" function that returns control back to the
	point of the setjmp invocation might cause memory associated
	with a variable length array object to be squandered.

	#include <setjmp.h>
	jmp_buf buf;
	void g(int n);
	void h(int n);
	int n = 6;

	void f(void) {
	   int x[n];        /* OK - "f" is not terminated */
	   setjmp(buf);
	   g(n);
	}

	void g(int n) {
	   int a[n];        /* "a" may remain allocated */
	   h(n);
	}

	void h(int n) {
	   int b[n];        /* "b" may remain allocated */
	   longjmp(buf,2);  /* might cause some memory to be lost */
	}

End of change.




      Language Syntax Summary
      -----------------------


	X.1.2.2 Declarations

	(6.5.4) direct-declarator:

	identifier

	(declarator)

	direct-declarator [assignment-expression   ]
					        opt
	direct-declarator [*   ]
			    opt
	direct-declarator (parameter-type-list)

	direct-declarator (identifier-list   )
					  opt

	(6.5.5) direct-abstract-declarator:

	(abstract-declarator)

	direct-abstract-declarator [assignment-expression   ]
						         opt
	direct-abstract-declarator [*   ]
				     opt
	direct-abstract-declarator (parameter-type-list   )
						       opt




=================================================================
===                                                           ===
===   Other correspondence you might be interested in reading ===
===                                                           ===
=================================================================

From [email protected] Tue Apr  1 15:04 CST 1997
Date: Tue, 1 Apr 97 14:03:29 MST
From: [email protected] (David Keaton)
To: [email protected]
Subject: Re: VLA Edits

TMacD> Basically, it allows you to keep adding more precise information.
TMacD> Don't know how useful this is in a program but still needs to be
TMacD> specified.

     Thanks.  Those examples helped.  I agree that the usefulness of
forming a composite type with an array of known constant size and a
VLA is questionable, but should be specified.

TMacD> An example for composite types is:
TMacD>
TMacD>    void f(int [ ][*]);
TMacD>    void f(int [5][5]);
TMacD>
TMacD> In the above case the composite type is:
TMacD>
TMacD>    void f(int [5][5]);
TMacD>
TMacD> and the parameter is no longer a VLA.

     It might be worthwhile to add this example just to make it
obvious.  However, since I don't think this technique will be used
very often, I won't object if you don't want to add it.

     That's the only issue I had with the VLA changes.

                                        David

========================================================================

From [email protected] Thu Apr  3 13:38 CST 1997
From: Thomas MacDonald <[email protected]>
Subject: Re: VLA Edits
To: [email protected] (David Keaton)
Date: Thu, 3 Apr 1997 13:37:41 -0600 (CST)


Thanks David.  I've thought about this and decided that this is
better left to rationale.  So, I'll keep the example around.

Tom MacDonald
[email protected]

========================================================================

From [email protected] Wed Apr 16 13:43 CDT 1997
Date: Wed, 16 Apr 1997 09:06:46 -0700
From: [email protected] (Douglas Walls)
To: [email protected], [email protected], [email protected]
Subject: Re: VLA Edits

Tom,

>Comments should be sent to me by April 15.

Naturally, as I draft these comments, we have network problems and I
am unable to send them on time.  Apologies for sending them a day late.

Douglas

---> %%
---> %% Change #7
---> %%
---> 
---> Add the following example to 6.3.6 Additive operators:
---> 
---> 	Pointer arithmetic is still well defined with pointers to
                              ^^^^^
    This reads as if we are trying to convince someone of the merits of
    the proposal.  Eliminating this word does not change the example's
    meaning.

---> 	variable length array types.

____________________

---> %%
---> %% Change #10
---> %%
---> 
---> 	6.5 Declarations
---> 
---> 	6.5.2 Type specifiers
---> 
---> Add the following as a Constraint:

  Just to make it clear where to place this constraint:

     Add the following as a new paragraph to the end of the Constraints:

---> 
---> 	Only ordinary identifiers (as defined in 6.1.2.3) with
---> 	block scope or function prototype scope and without linkage
---> 	can have a variably modified type.  If an identifier is
---> 	declared to be an object with static storage duration, it
---> 	shall not have a variable length array type.
---> 
---> End of change.

____________________

---> %%
---> %% Change 20
---> %%
---> 
---> Add the following examples to 6.5.4.2 Array declarators:

  Just to make it clear where to add this example:

     Add the following as example 3 to 6.5.4.2 Array declarators:
____________________

---> %%
---> %% Change 22
---> %%
---> 
---> Add the following examples to 6.5.4.3 Function declarators:

  Just to make it clear where to add this example:

     Add the following as examples 4 and 5 to 6.5.4.3 Function declarators:

____________________

---> %%
---> %% Change 25
---> %%
---> 
---> Add the following examples to 6.5.6 Type definitions:

  There are four examples int 6.5.6 now, each with a number and
  leading.  Where are these example suppose to go?

--->	void tdef(int n) {
--->	   typedef int A[n];   /* OK - declared with block scope */
--->	   A a;
--->	   A *p;
--->	   p = &a;
--->	}
--->
--->    void copyt(int n) {
--->       typedef int A[n]; /* A is n ints with n evaluated now */
--->       n += 1;
--->       {
--->          A a;           /* a is n ints - n without += 1 */
--->          int b[n];      /* a and b are different sizes */
--->          for (i = 1; i < n; i++)
--->             a[i-1] = b[i];
--->       }
--->    }
--->
---> End of change.

____________________

---> %%
---> %% Change 27
---> %%
---> 
---> 6.6.2 Compound statement, or block
---> 
---> 	[#2] A compound statement (also called a block) allows a set
---> 	of statements to be grouped into one syntactic unit, which
---> 	may have its own set of declarations and initializations (as
---> 	discussed in 6.1.2.4).  The initializers of objects that
---> 	have automatic storage duration,
                                       ^
  There is no comma in the original text.

---> 
---> Add the following words to paragraph 2 above:
---> 
---> 					and the variable length
  The comma belongs here --------------^

---> 	array declarators of ordinary identifiers with block scope
---> 	.......

End of change.
____________________

---> %%
---> %% Change 28
---> %%
---> 
---> 	6.6.4.2 The "switch" statement
---> 
---> 	[#1] The controlling expression of a "switch" statement shall
---> 	have integral type,
                          ^
  There is no comma in the original text.

---> 
---> Add the following words to paragraph 1 above:
---> 
---> 				and shall not cause a block to
  The comma belongs here-------^

---> 	be entered by a jump from outside the block to a statement
---> 	that follows a case or default label in the block (or an
---> 	enclosed block) if that block contains the declaration of a
---> 	variably modified object or variably modified typedef name.

End of change.
____________________

---> %%
---> %% Change 29
---> %%
---> 
---> Add the following example to 6.6.4.2 The switch statement:

  This example needs some lead in text.  Looking at the examples in
  6.6.4.2 it is not clear where this example is suppose to go.

---> 
---> 	switch (n)      /* Error - bypasses declaration of a[n] */
---> 	{
---> 	int a[n];
---> 	case 10:
---> 	   a[0] = 1;
---> 	   break;
---> 	case 20:
---> 	   a[0] = 2;
---> 	   break;
---> 	default:
---> 	   a[0] = 3;
---> 	   break;
---> 	}
---> 
---> End of change.
____________________

---> %%
---> %% Change 30
---> %%
---> 
---> 	6.6.6.1 The goto statement
---> 
---> Add the following Constraint to 6.6.6.1 The goto statement:

  Just to make it clear where to place this constraint:

     Add the following Constraint as new constraint 2 to 6.6.6.1 The
     goto statement:

____________________

---> %%
---> %% Change 31
---> %%

  Where does this change go?  How is it to be integrated with the
  existing example in 6.6.6.1?  Or are we missing some lead in text and
  placement?

---> 
---> 	goto lab3;  /* Error - going INTO scope of variable length array */
---> 	{
---> 	   double a[n];
---> 	   a[j] = 4.4;
---> 	lab3:
---> 	   a[j] = 3.3;
---> 	   goto lab4; /* OK - going WITHIN scope of variable length array */
---> 	   a[j] = 5.5;
---> 	lab4:
---> 	   a[j] = 6.6;
---> 	}
---> 	goto lab4; /* Error - going INTO scope of variable length array */
---> 
---> End of change.



From [email protected] Fri May  9 17:32 CDT 1997
From: Bill Homer <[email protected]>
Subject: Re: And this
To: [email protected] (Thomas MacDonald)
Date: Fri, 9 May 1997 17:32:55 -0500 (CDT)


Tom,

I did see a typo and also have a few suggestions, but none are crucial.
They are marked with '|' at the left.

- Bill


> %%
> %% Change #1
> %%
>
>         6.1.2.4 Storage duration of objects
>
>       [#3] An object whose identifier is declared with no linkage
>       and without the storage-class specifier static has automatic
>       storage duration.  Storage is guaranteed to be reserved for
>       a new instance of such an object on each normal entry into
>       the block with which it is associated.
                                             ^
|                       omit punctuation here, because it changes

> Replace the following words in C9XD9-pre3:
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
| End the sentence in C9XD9-pre3 here, and replace its final clause:

>
>                                               , or on a jump from
>       outside the block to a labeled statement in the block or in
>       an enclosed block.
>
> With the new complete sentences:
>
>                                               . If the block with
>       which the object is associated is entered by a jump from
>       outside the block to a labeled statement in the block or in
>       an enclosed block, then storage is guaranteed to be reserved
>       provided the object does not have a variable length array
>       type.  If the object is variably modified and the block is
>       entered by a jump to a labeled statement, then the behavior
>       is undefined.
>
> End of change.



> %%
> %% Change #4
> %%
>
>       6.3 Expressions
>
>       6.3.3.4 The "sizeof" operator
>
>       Semantics
>
>       [#2] The "sizeof" operator yields the size (in bytes) of its
>       operand, which may be an expression or the parenthesized
>       name of a type.
>
> Replace the following words in C9XD9-pre3:
>
>                       The size is determined from the type of the
>       operand, which is not itself evaluated.  The result is an
>       integer constant.
>
> With:
>
>       The size is determined from the type of the operand.
>       The result is an integer.  If the type of the operand
>       is a varaible length array type, the operand is evaluated;
             ^^^^^^^^
             variable
|

>       otherwise, the operand is not evaluated and the result is
>       an integer constant.
>
> End of change.



> %%
> %% Change #11
> %%
>
> Add the following example to 6.5.2 Type specifiers:
>
>       All declarations of Variably Modified (VM) types must be declared at
                            ^^^^^^^^^^^^^^^^^
| Why capitals here?  They are not used in other places.

>       either block scope or function prototype scope.  Array objects
>       declared with the "static" or "extern" storage class specifier cannot
>       have a Variable Length Array (VLA) type.  However, a object declared
               ^^^^^^^^^^^^^^^^^^^^^
| Why capitals here?  They are not used in other places.

>       with the "static" storage class specifier can have a VM type (that
>       is, a pointer to a VLA type).  Finally, all identifiers declared
>       with a VM type must be ordinary identifiers, and can not, therefore,
>       be members of structures or unions.
>
>       extern int n;
>       int A[n];                       /* Error - file scope VLA */
>       extern int (*p2)[n];            /* Error - file scope VM */
>       int B[100];                     /* OK - file scope but not VM */
>
>       void fvla(int m, int C[m][m]) { /* OK - VLA with prototype scope */
>          typedef int VLA[m][m];       /* OK - block scope typedef VLA */
>                                       /* array size m evaluated now */
>          struct tag {
>             int (*y)[n];       /* Error - y is not an ordinary identifier */
>             int z[n];          /* Error - z is not an ordinary identifier */
>          };
>          int D[m];                    /* OK - auto VLA */
>          static int E[m];             /* Error - static block scope VLA */
>          extern int F[m];             /* Error - F has linkage and is a VLA */
>          int (*s)[m];                 /* OK - auto pointer to VLA */
>          extern int (*r)[m]; /*Error - r has linkage and is a pointer to VLA*/
>          static int (*q)[m] = &B; /* OK - q is a static block scope VM */
>
>            /* ... */
>
>       }
>
> End of change.



> %%
> %% Change 22
> %%
>
> Add the following as examples 4 and 5 to 6.5.4.3 Function declarators:
>
>     4.  The following prototype has a variably modified parameter.
>
>       void addscalar(int n, int m, double a[n][n*m+300], double x);
>
>       main() {
>          double b[4][308];
>          addscalar(4, 2, b, 2.17);
>       }
>
>       void addscalar(int n, int m, double a[n][n*m+300], double x) {
>          int i, j, k=n*m+300;
>
>          for (i = 0; i < n; i++)
>             for (j = 0; j < k; j++)
>                a[i][j] += x;    /* a is a pointer to a VLA of size: n*m+300 */
                                                             ^^^^^^^^^^^^^^^^
|                                                        with n*m+300 elements

>       }
>
>
>     5.  The following are all compatible function prototype declarators.
>
>       double maximum(int n, int m, double a[n][m]);
>       double maximum(int n, int m, double a[*][*]);
>       double maximum(int n, int m, double a[ ][*]);
>       double maximum(int n, int m, double a[ ][m]);
>
> End of change.



> %%
> %% Change 28
> %%
>
>       6.6.4.2 The "switch" statement
>
>       [#1] The controlling expression of a "switch" statement shall
>       have integral type
>
> Add the following words to paragraph 1 above:
>
>                               , and shall not cause a block to
>       be entered by a jump from outside the block to a statement
>       that follows a case or default label in the block (or an
>       enclosed block) if that block contains the declaration of a
>       variably modified object or variably modified typedef name.

| Maybe this is too big a change, but it seems like there is a
| simpler alternative that is also statically checkable:

        If a declaration with a variably modified type is associated
        with a block that contains a case or default label of a switch
        statement, then that block shall contain the entire switch
        statement.

> End of change.



> %%
> %% Change 30
> %%
>
>       6.6.6.1 The goto statement
>
> Add the following constraint as the second sentence to the Constraints of
> 6.6.6.1 The goto statement:
>
>       A "goto" statement shall not cause a block to be entered by
>       a jump from outside the block to a labeled statement in
>       the block (or an enclosed block) if that block contains
>       the declaration of a variably modified object or
>       variably modified typedef name

| Analogous to the switch statement:

        If a declaration with a variably modified type is associated
        with a block that contains a label named in a goto statement,
        then that block shall also contain the goto statement.

> End of change.