On 06/27/2017 04:31 PM, Joseph Myers wrote:
On Tue, 27 Jun 2017, Martin Sebor wrote:
There's the usual question of what should be done with arrays
of qualified types (where C does not consider such an array type to be
qualified, but C++ considers it to have the same qualifiers as the element
type). There's also the matter of qualifiers used internally by GCC to
represent const and noreturn functions.
What about _Atomic? Should it also be removed? If yes, how would
I think so. I'd think of this as being something like type as an rvalue,
which is the unqualified, non-atomic version of the type. Which is
appropriate for various uses of type-generic macros where you declare
temporary variables, and there is no need for those temporaries to be
volatile, atomic, etc., even if the inputs or outputs for the macro are.
Yes, that would make sense to me.
one then generically define a cv-unqualified object of an atomic
type when given a const- or volatile-qualified atomic type or object?
I'm doubtful of the utility of that.
Given the novelty of the concept in C I don't think it's safe make
predictions about the utility of type-generic tools in the language.
The safest approach, IMO, is to take guidance from the experience
in C++ with its rich set of type traits including remove_const,
remove_volatile, and (to your later point) also remove_cv. These
weren't introduced to C++ in 1998. It took over a decade for
people to realize that they were not just useful but essential for
generic programming.
Yes, syntactically restrict is (kind of like) a qualifier, but
semantically it's nothing like it (the standard says it's more
akin to a storage specifier). Most (but not all) of the essential
Storage class specifiers aren't part of the type system at all. All the
usual rules for qualified types apply to restrict (whereas they *don't*
necessarily apply to _Atomic).
Sure. The difference is that restricted pointers carry with them
additional semantic constraints that other qualifiers don't, such
as those transfered by assigning a T* restrict to a T*. Or
the outer-to-inner assignment limitation. So while it looks like
a qualifier, I don't think restrict acts like one.
In my mind, all this speaks in favor of introducing simpler building
blocks. From its name alone, the expected effects of a __remove_const
or __remove_atomic built-in (not to mention their utility) are far
clearer than those of __typeof_noqual__.
If you *only* have blocks like that, you can't then write code that also
removes whatever qualifiers might be added in future - you keep needing to
update the generic code for future qualifiers. For C90 you'd have had
__remove_const and __remove_volatile, but then would have needed to update
again for restrict, again after that for address spaces, and again after
that for _Atomic.
I.e., just having blocks to remove qualifiers of kind X is not sufficient
without "remove all qualifiers (possibly except these kinds)" as well. I
suppose you could have __remove_quals (const volatile _Atomic, expr) and
__remove_quals_except (_Atomic, expr) or similar (with some keyword that
goes in there to mean "any address space").
Right. My point isn't that the bigger features shouldn't exist,
but that they can and should be built on top of the primitives
and defined not in the compiler but in a header. With
__bultin_remove_const() and __builtin_remove_volatile()
a __typeof_noqual(x) can be a macro that expands to these two,
plus any others as/if necessary, with any other additional
adjustments, again if/when necessary. This is the C++ approach;
it has worked well there and I think it would work well for C
too.
Martin