On 06/27/2017 11:50 AM, Joseph Myers wrote:
On Tue, 27 Jun 2017, Martin Sebor wrote:
Another thing, with the current patch, __typeof_noqual__(const int)
would still produce "const int". With the __atomic_load_n proposal
it'd return "int". I don't know what we want to do for typenames,
but __typeof__(_Atomic int) produces "atomic int".
I missed that. That seems surprising. I would expect the trait
to evaluate to the same type regardless of the argument (type or
expression). Why does it only strip qualifiers from expressions
and not also from types?
The type stripping from atomic expressions is basically what's necessary
for some stdatomic.h macros to work, while minimizing the risk to existing
code. Of course when adding _Atomic, anything whatever could have been
done with atomic types without risk to existing code, but I suppose there
is a case for thinking of typeof (typename) as being purely like
parentheses - not modifying the type at all.
I'd expect __typeof_noqual to remove qualifiers from both expressions and
type names.
I agree, although this discussion has made me even more convinced
that a set of simpler primitives would be preferable.
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
one then generically define a cv-unqualified object of an atomic
type when given a const- or volatile-qualified atomic type or object?
Unless __typeof__ (p) q = p; declares a restrict-qualified q when
p is a restrict-qualified pointer I don't think __remove_restrict
is needed. Restrict doesn't qualify a type but rather a pointer
object it applies to so I would find the effect above unexpected
restrict acts as a type qualifier in C terms, the type being
"restrict-qualifiers pointer to ...". I'd expect it to work just like
const and volatile in __typeof and __typeof_noqual.
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
properties of a restrict-qualified pointer also aren't removed by
removing the qualifier. Given a 'T restrict *p = &x; T *q = p;'
the pointer q is subject to the same aliasing constraints as p.
I'm pretty sure most users also expect the definition of q above
to be equivalent to '__typeof__(p) q = p;' If it weren't (and if
restrict were, in fact, part of the type extracted from p by
__typeof__), and applied to q then the assignment from p to q
would be undefined.
Conversely, if __typeof_noqual__ did remove the restrict qualifier
(as I agree it should), then similarly to the _Atomic question above,
how would one define a pointer q of the (non-restricted) type T when
given a restrict-qualified pointer p to T such that the assignment
(q = p) didn't also discard const or volatile (or _Atomic) qualifiers?
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__.
Martin