Name n3629, alx-0004r3 - Adopt qualifier conversion rules from C++ Principles - Codify existing practice to address evident deficiencies. - Do not leave features in an underdeveoped state. - Enable secure programming. - Facilitate interoperability. Category Language; conversions; pointers. Author Alejandro Colomar Cc: Jonathan Wakely Cc: Joseph Myers Cc: наб Cc: Christopher Bazley History r0 (2025-03-15): - Initial draft. r1 (2025-03-17): - Fix recursive wording. The types in tN might be qualified at any level as long as the corresponding uN is qualified, regardless of the qualification of t(N-1). At least that's what g++(1) seems to accept. r2 (2025-05-04): - Fix typos. - Remove bogus link from 'See also'. - Add links to 'See also'. - Mention n3510 in 'See also'. - Use the wording in C++11. The wording I had was bogus; and the wording in the current versions of C++ is too complex for me to understand it. The wording of C++11 is slightly less powerful than the current one, but on the other hand it's not a bad idea to fall short on allowed conversions, just in case. If we want to lift more restrictions, we're always in time. r3 (2025-06-29; n3629): - Complete reword, using wording from n3510 (Bazley; "Enhanced type variance (v2)"). This is even simpler than the wording from C++11 I had picked earlier, and works much better (I don't need to add extra wording to make it work with the existing standard). Description C is too strict regarding qualifiers, and requires the programmer to do casts or have functions with unnecessarily unqualified APIs. C++ has shown that certain assignments can be done safely. The following is forbidden by C, but allowed by C++: char *p; const char *const *pp = &p; See also This proposal would interact with n3510 (see link above). Both proposals intend to reduce the use of casts for converting pointers, in order to have stronger type safety. n3510 focuses on function pointers, while this proposal focuses on pointers to pointers. Both proposals are compatible (and beneficial to eachother), although care should be taken to make sure there are no merge conflicts. This proposal should be simpler than n3510, since we have prior art in C++, where it has been tested for a long time. Proposed wording Based on N3550. 6.2 Concepts ## Add new subsection after 6.2.7 ("Compatible type and composite type") +6.2.7+1 Substitutable type +1 + In certain circumstances, + an expression of pointer type + can be assigned to + an lvalue of a different pointer type. + In such cases, + the referenced type of the assigned expression + is said to be substitutable for + the referenced type of the lvalue to which it is assigned. + One type can be substitutable for multiple types. +2 + A type, Q, + is substitutable for another type, R, + if the following conditions are satisfied: + + -- Q and R + would be compatible types + if all qualifiers except _Atomic + were removed from both types, + including recursively the pointed-to types + in derived pointer types. + -- For every referenced type + from which a pointer is derived + (including recursively) + and the type itself: + -- the type in R + has all the qualifiers + of the type in Q; and, + -- the type in Q + has an atomic type + if the type in R + has an atomic type; and, + -- the type in R + is const-qualified + if it is a pointer type + derived from a referenced type + for which Q + does not have all the qualifiers + of the type in R. 6.5.17.2 Expressions :: Assignment operators :: Simple assignment @@ Constraints, p1 One of the following shall hold:113) -- [...] -- [...] -- the left operand has an atomic, qualified, of unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to - qualified or unqualified versions of compatible types, - and the type pointed to by the left operand - has all the qualifiers - of the type pointed to by the right operand; + or + the referenced type of the right operand + is substitutable for + the referenced type of the left operand; -- [...] ...