On 06/27/2017 07:14 AM, Marek Polacek wrote:
On Mon, Jun 26, 2017 at 10:37:03AM -0600, Martin Sebor wrote:
On 06/23/2017 08:46 AM, Marek Polacek wrote:
This patch adds a variant of __typeof, called __typeof_noqual.  As the name
suggests, this variant always drops all qualifiers, not just when the type
is atomic.  This was discussed several times in the past, see e.g.
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39985>
or
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65455>
It's been brought to my attention again here:
<https://gcc.gnu.org/ml/gcc-patches/2017-05/msg01955.html>

One approach would be to just modify the current __typeof, but that could
cause some incompatibilities, I'm afraid.  This is based on rth's earlier
patch: <https://gcc.gnu.org/ml/gcc-patches/2016-02/msg00268.html> but I
didn't do the address space-stripping variant __typeof_noas.  I also added
a couple of missing things.

I haven't reviewed all the discussions super carefully so I wonder
what alternatives have been considered.  For instance, it seems to
me that it should be possible to emulate __typeof_noqual__ by relying
on the atomic built-ins' type-genericity.  E.g., like this:

  #define __typeof_noqual__(x) \
    __typeof__ (__atomic_load_n ((__typeof__ (x)*)0, 0))

This doesn't seem to work with structs/arrays/VLA, so wouldn't help.
(typeof can't handle bit-fields, so no need to worry about those.)

You're right, it doesn't appear to work the way I thought.  I was
misled by a poor warning message into believing it did.  But it
seems that it should work.  atomic_load() is specified (with DR
459 applied) to take a const volatile _Atomic T* argument and
return a plain T.  Or is there a problem I'm missing?  (Btw.,
I used the atomic built-in only as an example of the approach
I was thinking of, hoping someone would come up with a better
built-in or other existing extension to make the solution look
less hacky.)


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 __typeof__(_Atomic T) example lends support to the idea of
more primitive traits.  It's not hard to envision use cases where
one might be interested in obtaining the underlying (non-atomic)
type of an expression or type without losing its cv qualifiers,
or vice versa.


Alternatively, adding support for lower-level C-only primitives like
__remove_const and __remove_volatile, to parallel the C++ library
traits, might provide a more general solution and avoid introducing
yet another mechanism for determining the type of an expression to
the languages (C++ already has a few).

I don't know if that wouldn't be overkill.  Qualifiers on rvalues are
meaningless in C and that's why my __typeof_noqual strips them all.
We'd then need even e.g. __remove_restrict, not sure if there's need for
these.  Maybe it is.

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
(notwithstanding the fact that a copy of a restricted pointer is
subject to some of the same constraints as the original even
without the qualification).

I would expect the other remove traits to be useful.  People
have been experimenting with generic programming in C (e.g.,
https://gcc.gnu.org/ml/gcc/2017-05/msg00082.html).  WG14 is
considering a proposal to add const-correct overloads of many
of the string functions (like strchr) that relies on a (very
simple) form of it.  The proposal's author (and the submitter
of PR 65455) also has done a lot of work in this space
(detecting/removing/adding qualifiers).  I don't have nearly
as much experience with this type of programming in C but the
lesson I learned from my work on C++ type traits is that where
a more complex feature can be decomposed into two or more
smaller, primitive ones, the latter sooner or later end up
being needed in other contexts as well and make valuable
general-purpose features on their own.


+@code{typeof_noqual} behaves the same except that it strips type qualifiers
+such as @code{const} and @code{volatile}, if given an expression.  This can
+be useful for certain macros when passed const arguments:
+
+@smallexample
+#define MAX(__x, __y)                  \
+  (@{                                  \
+  __typeof_noqual(__x) __ret = __x;    \
+  if (__y > __ret) __ret = __y;             \
+    __ret;                             \
+  @})

The example should probably avoid using reserved names (with
leading/double underscores).

No, because "typeof_noqual" isn't supported (but was in the first version
of the patch).

I was referring to the underscores in the names of the macro
arguments and the temporary variable, not the new keyword.

Martin

Reply via email to