ISO/ IEC JTC1/SC22/WG14 N754

        Proposal to Relax the Rules for Qualification Conversions
        of Pointers in the C9X Programming Language

                         Document Number:  WG14 N754/J11 97-117
                               C9X Revision Proposal
       Title:  Relax the Rules for Qualification Conversions
       Author: J.G.Krom
       Author Affiliation: Jet Joint Undertaking
       Postal Address: Abingdon, OX14 3EA, UK
       E-mail Address:
       Telephone Number: +44 1235 464481
       Fax Number: +44 1235 464404
       Sponsor: (Undecided as yet)
       Date: 1997-08-26
       Proposal Category:
          __ Editorial change/non-normative contribution
          X_ Correction
          __ New feature
          __ Addition to obsolescent feature list
          __ Addition to Future Directions
          __ Other (please specify)
       Area of Standard Affected:
          __ Environment
          X_ Language
          __ Preprocessor
          __ Library
             __ Macro/typedef/tag name
             __ Function
             __ Header
          __ Other (please specify)
       Prior Art: 
          C++ has similar relaxed rules. C needs them.
       Target Audience: 
          All programmers interested in const-correct coding.
       Related Documents (if any): 
       Proposal Attached: X_ Yes __ No, but what's your interest?
          This paper points out a problem using the const 
          qualifier with one the main data-structures of 
          the C language.  A proposal is presented that will
          correct this problem.  
          Follows below.



The type qualifier "const" was added to the C language during the
standardisation process in the late 1980's.  It is often used in
function prototypes to indicate that the function will not modify 
its arguments; e.g. the prototype

	void f ( const char * p );

indicates that this function f() will not modify the character(s)
pointed at by p (i.e. it will not modify *p).

However, the current standard C rules for the use of this qualifier
are not 100% complete or consistent.  These rules conflict with some 
of the important data structures defined in the C language.


1.1 NO WAY TO HANDLE argv AS A const

One of the main problems is that, with the current C standard, it is 
not possible to write the prototype for a function g() that takes the
second argument of main() as its input and that promises that this
function will not modify this argv data-structure.

        void f ( const char * p);
        void g ( /* some const qualified variant of */ char ** p);
        int main ( int argc, char * argv[] )
                /* argv[0] is not modified by f() */

                /* Has argv been modified by g() ? */

What should the prototype of g() be, so that it promises that calling
g() will not affect the argv data structure ?  Well, within current
standard C it is impossible to give g() such a prototype.



Another effect of this is that a closely related, often used and
idiomatic data-structure cannot be used in a type-correct way.  
See the following code fragment:

        void g ( /* some const qualified variant of */ char ** p);
        int main ( int argc, char * argv[] )
                const char * dummyargs[] =
                        {"A", "dummy", "argument", "array", 0};


In this fragment g() will be called once with a "char **" argument 
and once with a "const char **".  In the current C language, it is
impossible to give g() a prototype so that the function could be 
used in this way.



The rules for parameter type-checking during a function call (to a
prototyped function) are essentially (by section those that
apply to an assignment.  The function prototype problems indicated 
above are the results of the fact that the last of the assignments 
in the following code fragment is currently type-incorrect:

                char       * cp
                char       * const *  cpcp  = &cp; /* legal */
                const char * const * ccpcp  = &cp; /* illegal */

There is however little, if any, reason to consider the last assignment
type-incorrect.  Since ccpcp points to a constant pointer, that points
to a const char, it cannot be used to modify any characters, or
intermediate pointers, pointed to.

The C language could safely allow this assignment.



There is a safe way to expand the current assignment rules, that would
solve the above mentioned problems.  The proposal is a generalisation of
the idea to allow the assignment marked "/* illegal */" in the
above fragment.

The proposal applies not only to a "pointer to a pointer", but also to
types representing longer chains of pointers.  It further also applies to
all qualifiers (although the rules are not the same for "const" and
"volatile").  This causes the actual proposal to look rather complicated.

The proposal is in three parts.  The first (proposal part A) is only an
editorial proposal that allows the text of the main proposal to be a
written in a slightly more concise notation.  The second part (proposal
part B) is the main proposal.

The last part (proposal part C) specifies some changes required to the
existing text of the standard.

The text of the current proposal is directly derived from a far larger
proposal by Thomas Plum, dated 1994-12-14.  Mr. Plum proposed these
changes in a different context (that of C++ compatibility), but as
indicated above there are also good reasons within the C language to
adopt this proposal.


2.1 PROPOSAL PART A [Editorial]

Use the abbreviation cv (when possible in italics) for "possibly-qualified"

	In this document, the notation cv (or cv1, cv1,2, etc.), used in
	the description of types, represents an arbitrary set of
	cv-qualifiers, i.e., one of
		{const, volatile},
		{const, restrict},
		{volatile, restrict},
		{const, volatile, restrict},
		or the empty set.

	cv-qualifiers applied to an array type attach to the underlying
	element type, so the notation cvT, where T is an array type,
	refers to an array whose elements are so-qualified.  Such array
	types can be said to be more (or less) cv-qualified than other
	types based on the cv-qualification of the underlying element

Rationale: Brevity.  The restrict qualifier has been added, others might
be added later.  Still, the brevity of cv is attractive.



Relax the rules for qualification conversions of pointers

	Qualification Conversions

	An rvalue of type pointer to cv1T can be converted to an rvalue
	of type pointer to cv2T if cv2T is more cv-qualified than cv1T.

	A conversion can add type qualifiers at levels other than the
	first in multi-level pointers, subject to the following rules:[*]

	Two pointer types T1 and T2 are  similar if there exists a type
	T* and integer n>0 such that:

		T1 is T cv1,n *  . . .  cv1,1 * cv1,0
		T2 is T cv2,n *  . . .  cv2,1 * cv2,0

	where each cvi,j is a combination of one or more of the
	qualifiers "const", "volatile", "restrict" or nothing.

	An expression of type T1 can be converted to type T2 if and only
	if the following conditions are satisfied:

	--- the pointer types are similar.

	--- for every j>0, if const is in cv1,j then "const" is in cv2,j,
	    and similarly for "volatile" and "restrict".

	--- the cv1,j and cv2,j are different, then "const" is in every
	    cv2,k for 0<k<j, 
	    and similarly for "restrict" (but not for "volatile").

	Footnote [*]: These rules ensure that const-safety is preserved
	by the conversion.  This conversion never applies to non-static
	member functions because there is no way to obtain an lvalue for
	a non-static member function.

The text of parts A and B of the proposal can be combined into one,
numbered, paragraph. This paragraph could be located immediately after
section, because of its relationship with compatible types.
Alternatively it could be placed close to section 6.5.3 because of its
relationship with qualified types.



Adapt the text of section in order to use the relaxed
qualification conversions.

	In section, "Simple assignment", the third constraint
	currently states:

	--- Both operands [of a simple assignment] are pointers to
	qualified or unqualified versions of compatible types, and the
	type pointed to by the left has all the qualifiers of the type
	pointed at by the right. 

	This constraint should at least be depreciated, it probably can 
	be removed altogether.

	A new constraint should be added to this section:

	--- Both operands [of a simple assignment] are pointers to
	compatible types, and the qualifiers of the type pointed at by
	the right operand can be converted to the type pointed at by the
	left operand, according to the rules in section Qualification
	Conversions [to be replaced by the appropriate section number].



The proposal would allow assignments to be made that are currently
forbidden.  This means that no existing code uses these assignments.
Even if some code exist that ignores any compiler warnings and uses
such an assignments, it could only meaningfully do so to obtain the
semantics currently proposed.

The assignments that this proposal would allow are completely safe with
respect to the "const" and "volatile" qualifiers.  (It only changes the
rules for "const"; the rule for "volatile" is essentially still what it 
was in C89.)

[[A further elaborated version of this proposal should include some
support for this statement.]]

I do not have enough information to judge the effects on the "restrict"
qualifier.  Although the first impression is that handling "restrict" 
in the same way as "const" ought to be safe, this is better checked by
someone with more detailed knowledge of "restrict".



The C++ language already successfully allows assignments as are proposed
in this paper for C.  The actual wording of the proposal is derived from
the wording in the C++ (draft) standard.

However, this proposal is not presented as an attempt to make C and
C++  more compatible, but as attempt to correct a feature of the C