public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
@ 2017-06-23 14:46 Marek Polacek
  2017-06-23 14:48 ` Jakub Jelinek
                   ` (2 more replies)
  0 siblings, 3 replies; 22+ messages in thread
From: Marek Polacek @ 2017-06-23 14:46 UTC (permalink / raw)
  To: GCC Patches, Jason Merrill, Joseph Myers

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.

You'll also see that I dropped all qualifiers for __auto_type.  But I actually
couldn't trigger the
init_type = c_build_qualified_type (init_type, TYPE_UNQUALIFIED);
line in c_parser_declaration_or_fndef (even when running the whole testsuite)
so I'm not convinced it makes any difference.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2017-06-23  Marek Polacek  <polacek@redhat.com>
	    Richard Henderson  <rth@redhat.com>

	PR c/65455
	PR c/39985
	* c-common.c (c_common_reswords): Add __typeof_noqual,
	__typeof_noqual__, and typeof_noqual.
	(keyword_begins_type_specifier): Handle RID_TYPEOF_NOQUAL.
	* c-common.h (enum rid): Add RID_TYPEOF_NOQUAL.

	* c-parser.c (c_keyword_starts_typename): Handle RID_TYPEOF_NOQUAL.
	(c_token_starts_declspecs): Likewise.
	(c_parser_declaration_or_fndef): Always strip all qualifiers for
	__auto_type.
	(c_parser_declspecs): Handle RID_TYPEOF_NOQUAL.
	(c_parser_typeof_specifier): Handle RID_TYPEOF_NOQUAL by dropping
	all the qualifiers.
	(c_parser_objc_selector): Handle RID_TYPEOF_NOQUAL.

	* parser.c (cp_keyword_starts_decl_specifier_p): Handle RID_TYPEOF_NOQUAL.
	(cp_parser_simple_type_specifier): Handle RID_TYPEOF_NOQUAL by dropping
	all the qualifiers.

	* doc/extend.texi: Document __typeof_noqual.
	* doc/invoke.texi: Update documentation regarding typeof.

	* c-c++-common/typeof-noqual-1.c: New test.
	* c-c++-common/typeof-noqual-2.c: New test.
	* gcc.dg/typeof-noqual-1.c: New test.


diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c
index f6a9d05..db9c3ba 100644
--- gcc/c-family/c-common.c
+++ gcc/c-family/c-common.c
@@ -433,6 +433,8 @@ const struct c_common_resword c_common_reswords[] =
   { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 },
   { "__typeof",		RID_TYPEOF,	0 },
   { "__typeof__",	RID_TYPEOF,	0 },
+  { "__typeof_noqual",	RID_TYPEOF_NOQUAL, 0 },
+  { "__typeof_noqual__", RID_TYPEOF_NOQUAL, 0 },
   { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
   { "__volatile",	RID_VOLATILE,	0 },
   { "__volatile__",	RID_VOLATILE,	0 },
@@ -506,6 +508,7 @@ const struct c_common_resword c_common_reswords[] =
   { "typename",		RID_TYPENAME,	D_CXXONLY | D_CXXWARN },
   { "typeid",		RID_TYPEID,	D_CXXONLY | D_CXXWARN },
   { "typeof",		RID_TYPEOF,	D_ASM | D_EXT },
+  { "typeof_noqual",	RID_TYPEOF_NOQUAL, D_ASM | D_EXT },
   { "union",		RID_UNION,	0 },
   { "unsigned",		RID_UNSIGNED,	0 },
   { "using",		RID_USING,	D_CXXONLY | D_CXXWARN },
@@ -7511,6 +7514,7 @@ keyword_begins_type_specifier (enum rid keyword)
     case RID_SAT:
     case RID_COMPLEX:
     case RID_TYPEOF:
+    case RID_TYPEOF_NOQUAL:
     case RID_STRUCT:
     case RID_CLASS:
     case RID_UNION:
diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h
index 1748c19..3d98697 100644
--- gcc/c-family/c-common.h
+++ gcc/c-family/c-common.h
@@ -100,8 +100,9 @@ enum rid
   /* C extensions */
   RID_ASM,       RID_TYPEOF,   RID_ALIGNOF,  RID_ATTRIBUTE,  RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_CHOOSE_EXPR,
-  RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	     RID_BUILTIN_SHUFFLE,
-  RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
+  RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,
+  RID_BUILTIN_SHUFFLE, RID_DFLOAT32, RID_DFLOAT64,  RID_DFLOAT128,
+  RID_TYPEOF_NOQUAL,
 
   /* TS 18661-3 keywords, in the same sequence as the TI_* values.  */
   RID_FLOAT16,
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index 6f954f2..9899592 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -495,6 +495,7 @@ c_keyword_starts_typename (enum rid keyword)
     case RID_STRUCT:
     case RID_UNION:
     case RID_TYPEOF:
+    case RID_TYPEOF_NOQUAL:
     case RID_CONST:
     case RID_ATOMIC:
     case RID_VOLATILE:
@@ -671,6 +672,7 @@ c_token_starts_declspecs (c_token *token)
 	case RID_STRUCT:
 	case RID_UNION:
 	case RID_TYPEOF:
+	case RID_TYPEOF_NOQUAL:
 	case RID_CONST:
 	case RID_VOLATILE:
 	case RID_RESTRICT:
@@ -1873,8 +1875,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 			      " initializer");
 		  init = convert_lvalue_to_rvalue (init_loc, init, true, true);
 		  tree init_type = TREE_TYPE (init.value);
-		  /* As with typeof, remove all qualifiers from atomic types.  */
-		  if (init_type != error_mark_node && TYPE_ATOMIC (init_type))
+		  /* As with typeof_noqual, remove all qualifiers.  */
+		  if (init_type != error_mark_node)
 		    init_type
 		      = c_build_qualified_type (init_type, TYPE_UNQUALIFIED);
 		  bool vm_type = variably_modified_type_p (init_type,
@@ -2555,6 +2557,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	  declspecs_add_type (loc, specs, t);
 	  break;
 	case RID_TYPEOF:
+	case RID_TYPEOF_NOQUAL:
 	  /* ??? The old parser rejected typeof after other type
 	     specifiers, but is a syntax error the best way of
 	     handling this?  */
@@ -3218,7 +3221,10 @@ c_parser_typeof_specifier (c_parser *parser)
   ret.spec = error_mark_node;
   ret.expr = NULL_TREE;
   ret.expr_const_operands = true;
-  gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
+
+  enum rid keyword = c_parser_peek_token (parser)->keyword;
+  gcc_assert (keyword == RID_TYPEOF || keyword == RID_TYPEOF_NOQUAL);
+
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
   in_typeof++;
@@ -3260,7 +3266,9 @@ c_parser_typeof_specifier (c_parser *parser)
       /* For use in macros such as those in <stdatomic.h>, remove all
 	 qualifiers from atomic types.  (const can be an issue for more macros
 	 using typeof than just the <stdatomic.h> ones.)  */
-      if (ret.spec != error_mark_node && TYPE_ATOMIC (ret.spec))
+      if (ret.spec != error_mark_node
+	  /* __typeof_noqual also drops the qualifiers.  */
+	  && (TYPE_ATOMIC (ret.spec) || keyword == RID_TYPEOF_NOQUAL))
 	ret.spec = c_build_qualified_type (ret.spec, TYPE_UNQUALIFIED);
     }
   c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
@@ -9709,6 +9717,7 @@ c_parser_objc_selector (c_parser *parser)
     case RID_ASM:
     case RID_SIZEOF:
     case RID_TYPEOF:
+    case RID_TYPEOF_NOQUAL:
     case RID_ALIGNOF:
     case RID_UNSIGNED:
     case RID_LONG:
diff --git gcc/cp/parser.c gcc/cp/parser.c
index ddb1cf3..830b5b0 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -976,6 +976,7 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
       /* GNU extensions.  */ 
     case RID_ATTRIBUTE:
     case RID_TYPEOF:
+    case RID_TYPEOF_NOQUAL:
       /* C++0x extensions.  */
     case RID_DECLTYPE:
     case RID_UNDERLYING_TYPE:
@@ -16834,6 +16835,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       break;
 
     case RID_TYPEOF:
+    case RID_TYPEOF_NOQUAL:
       /* Consume the `typeof' token.  */
       cp_lexer_consume_token (parser->lexer);
       /* Parse the operand to `typeof'.  */
@@ -16841,6 +16843,9 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       /* If it is not already a TYPE, take its type.  */
       if (!TYPE_P (type))
 	type = finish_typeof (type);
+      /* If requested, make the type unqualified.  */
+      if (token->keyword == RID_TYPEOF_NOQUAL && type != error_mark_node)
+	type = cp_build_qualified_type (type, TYPE_UNQUALIFIED);
 
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
diff --git gcc/doc/extend.texi gcc/doc/extend.texi
index 43f9ecf..b323ecd 100644
--- gcc/doc/extend.texi
+++ gcc/doc/extend.texi
@@ -155,7 +155,8 @@ the value of an enumeration constant, the width of a bit-field, or
 the initial value of a static variable.
 
 If you don't know the type of the operand, you can still do this, but you
-must use @code{typeof} or @code{__auto_type} (@pxref{Typeof}).
+must use @code{typeof}, @code{typeof_noqual}, or @code{__auto_type}
+(@pxref{Typeof}).
 
 In G++, the result value of a statement expression undergoes array and
 function pointer decay, and is returned by value to the enclosing
@@ -642,6 +643,7 @@ myopen (const char *path, int oflag, ...)
 @node Typeof
 @section Referring to a Type with @code{typeof}
 @findex typeof
+@findex typeof_noqual
 @findex sizeof
 @cindex macros, types of arguments
 
@@ -694,6 +696,22 @@ arithmetic type and evaluates each of its arguments exactly once:
     _a > _b ? _a : _b; @})
 @end smallexample
 
+@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;				\
+  @})
+
+const int ci = 5;
+MAX (ci, 12);
+@end smallexample
+
 @cindex underscores in variables in macros
 @cindex @samp{_} in variables in macros
 @cindex local variables in macros
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index 7c81f0d..de1ff3d 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -1738,17 +1738,17 @@ equivalent to @option{-std=c++98}.
 
 This turns off certain features of GCC that are incompatible with ISO
 C90 (when compiling C code), or of standard C++ (when compiling C++ code),
-such as the @code{asm} and @code{typeof} keywords, and
+such as the @code{asm}, @code{typeof}, and @code{typeof_noqual} keywords, and
 predefined macros such as @code{unix} and @code{vax} that identify the
 type of system you are using.  It also enables the undesirable and
 rarely used ISO trigraph feature.  For the C compiler,
 it disables recognition of C++ style @samp{//} comments as well as
 the @code{inline} keyword.
 
-The alternate keywords @code{__asm__}, @code{__extension__},
-@code{__inline__} and @code{__typeof__} continue to work despite
-@option{-ansi}.  You would not want to use them in an ISO C program, of
-course, but it is useful to put them in header files that might be included
+The alternate keywords @code{__asm__}, @code{__extension__}, @code{__inline__},
+@code{__typeof__}, and @code{__typeof_noqual__} continue to work despite
+@option{-ansi}.  You would not want to use them in an ISO C program, of course,
+but it is useful to put them in header files that might be included
 in compilations done with @option{-ansi}.  Alternate predefined macros
 such as @code{__unix__} and @code{__vax__} are also available, with or
 without @option{-ansi}.
@@ -1949,17 +1949,18 @@ supported for C as this construct is allowed by C++.
 
 @item -fno-asm
 @opindex fno-asm
-Do not recognize @code{asm}, @code{inline} or @code{typeof} as a
-keyword, so that code can use these words as identifiers.  You can use
-the keywords @code{__asm__}, @code{__inline__} and @code{__typeof__}
-instead.  @option{-ansi} implies @option{-fno-asm}.
-
-In C++, this switch only affects the @code{typeof} keyword, since
-@code{asm} and @code{inline} are standard keywords.  You may want to
-use the @option{-fno-gnu-keywords} flag instead, which has the same
+Do not recognize @code{asm}, @code{inline}, @code{typeof} or
+@code{typeof_noqual} as a keyword, so that code can use these words as
+identifiers.  You can use the keywords @code{__asm__}, @code{__inline__},
+@code{__typeof__}, and @code{__typeof_noqual__} instead.  @option{-ansi}
+implies @option{-fno-asm}.
+
+In C++, this switch only affects the @code{typeof} and @code{typeof_noqual}
+keywords , since @code{asm} and @code{inline} are standard keywords.  You may
+want to use the @option{-fno-gnu-keywords} flag instead, which has the same
 effect.  In C99 mode (@option{-std=c99} or @option{-std=gnu99}), this
-switch only affects the @code{asm} and @code{typeof} keywords, since
-@code{inline} is a standard keyword in ISO C99.
+switch only affects the @code{asm}, @code{typeof}, and @code{typeof_noqual}
+keywords, since @code{inline} is a standard keyword in ISO C99.
 
 @item -fno-builtin
 @itemx -fno-builtin-@var{function}
@@ -2436,8 +2437,9 @@ otherwise be invalid, or have different behavior.
 
 @item -fno-gnu-keywords
 @opindex fno-gnu-keywords
-Do not recognize @code{typeof} as a keyword, so that code can use this
-word as an identifier.  You can use the keyword @code{__typeof__} instead.
+Do not recognize @code{typeof} and @code{typeof_noqual }as a keyword, so that
+code can use this word as an identifier.  You can use the keyword
+@code{__typeof__} or @code{__typeof_noqual__} instead.
 This option is implied by the strict ISO C++ dialects: @option{-ansi},
 @option{-std=c++98}, @option{-std=c++11}, etc.
 
diff --git gcc/testsuite/c-c++-common/typeof-noqual-1.c gcc/testsuite/c-c++-common/typeof-noqual-1.c
index e69de29..455e51f 100644
--- gcc/testsuite/c-c++-common/typeof-noqual-1.c
+++ gcc/testsuite/c-c++-common/typeof-noqual-1.c
@@ -0,0 +1,42 @@
+/* PR c/65455 */
+/* { dg-do compile } */
+/* { dg-options "-pedantic-errors" } */
+
+void
+foo (void)
+{
+  int i = 0;
+  const int ci = 0;
+  volatile int vi = 0;
+
+  __typeof(i) *ip = 0;
+  __typeof(ci) *cip = 0;
+  __typeof(vi) *vip = 0;
+
+  __typeof_noqual(i) *nip = 0;
+  __typeof_noqual(ci) *ncip = 0;
+  __typeof_noqual(vi) *nvip = 0;
+
+  __typeof_noqual__(i) *nip2 = 0;
+  __typeof_noqual__(ci) *ncip2 = 0;
+  __typeof_noqual__(vi) *nvip2 = 0;
+
+  ip = cip;		/* { dg-error "assignment discards|invalid conversion" } */
+  ip = vip;		/* { dg-error "assignment discards|invalid conversion" } */
+
+  ip = nip;
+  ip = ncip;
+  ip = nvip;
+
+  ip = nip2;
+  ip = ncip2;
+  ip = nvip2;
+
+  ncip = cip;		/* { dg-error "assignment discards|invalid conversion" } */
+  nvip = vip;		/* { dg-error "assignment discards|invalid conversion" } */
+  ncip2 = cip;		/* { dg-error "assignment discards|invalid conversion" } */
+  nvip2 = vip;		/* { dg-error "assignment discards|invalid conversion" } */
+
+  nip = ip;
+  nip2 = ip;
+}
diff --git gcc/testsuite/c-c++-common/typeof-noqual-2.c gcc/testsuite/c-c++-common/typeof-noqual-2.c
index e69de29..c1c07d5 100644
--- gcc/testsuite/c-c++-common/typeof-noqual-2.c
+++ gcc/testsuite/c-c++-common/typeof-noqual-2.c
@@ -0,0 +1,35 @@
+/* PR c/65455 */
+/* { dg-do compile } */
+/* { dg-options "-fgnu-keywords" { target c++ } } */
+
+const int g(void);
+
+#define MAX(__x, __y)			\
+  ({					\
+  __typeof_noqual(__x) __ret = __x;	\
+  if (__y > __ret) __ret = __y;		\
+    __ret;				\
+  })
+
+void
+fn (void)
+{
+  const int ci = 5;
+  __typeof_noqual (({ ci; })) n1;
+  __typeof_noqual (ci) n2;
+  __typeof (g ()) n4;
+  __typeof_noqual (g ()) n3;
+  typeof_noqual (ci) n6;
+
+  typedef __typeof_noqual(ci) T;
+  T n5;
+
+  n1 = 5;
+  n2 = 5;
+  n3 = 5;
+  n4 = 5;
+  n5 = 5;
+  n6 = 5;
+
+  MAX (ci, 12);
+}
diff --git gcc/testsuite/gcc.dg/typeof-noqual-1.c gcc/testsuite/gcc.dg/typeof-noqual-1.c
index e69de29..ec72506 100644
--- gcc/testsuite/gcc.dg/typeof-noqual-1.c
+++ gcc/testsuite/gcc.dg/typeof-noqual-1.c
@@ -0,0 +1,23 @@
+/* PR c/65455 */
+/* { dg-do compile } */
+/* { dg-options "-Wrestrict" } */
+
+int *restrict t;
+
+void
+bar (__typeof_noqual (t) p, __typeof_noqual (t) q)
+{
+}
+
+void
+baz (__typeof (t) p, __typeof (t) q)
+{
+}
+
+void
+foo (void)
+{
+  int i = 42;
+  bar (&i, &i);
+  baz (&i, &i); /* { dg-warning "passing argument 1 to restrict-qualified parameter aliases" } */
+}

	Marek

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-23 14:46 C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985) Marek Polacek
@ 2017-06-23 14:48 ` Jakub Jelinek
  2017-06-23 15:05   ` Marek Polacek
  2017-06-23 16:28 ` Joseph Myers
  2017-06-26 16:37 ` Martin Sebor
  2 siblings, 1 reply; 22+ messages in thread
From: Jakub Jelinek @ 2017-06-23 14:48 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jason Merrill, Joseph Myers

On Fri, Jun 23, 2017 at 04:46:06PM +0200, Marek Polacek wrote:
> +++ gcc/c-family/c-common.c
> @@ -433,6 +433,8 @@ const struct c_common_resword c_common_reswords[] =
>    { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 },
>    { "__typeof",		RID_TYPEOF,	0 },
>    { "__typeof__",	RID_TYPEOF,	0 },
> +  { "__typeof_noqual",	RID_TYPEOF_NOQUAL, 0 },
> +  { "__typeof_noqual__", RID_TYPEOF_NOQUAL, 0 },
>    { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
>    { "__volatile",	RID_VOLATILE,	0 },
>    { "__volatile__",	RID_VOLATILE,	0 },
> @@ -506,6 +508,7 @@ const struct c_common_resword c_common_reswords[] =
>    { "typename",		RID_TYPENAME,	D_CXXONLY | D_CXXWARN },
>    { "typeid",		RID_TYPEID,	D_CXXONLY | D_CXXWARN },
>    { "typeof",		RID_TYPEOF,	D_ASM | D_EXT },
> +  { "typeof_noqual",	RID_TYPEOF_NOQUAL, D_ASM | D_EXT },

Do you think we need this one?  Wouldn't just __typeof_noqual and
__typeof_noqual__ be sufficient?

	Jakub

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-23 14:48 ` Jakub Jelinek
@ 2017-06-23 15:05   ` Marek Polacek
  0 siblings, 0 replies; 22+ messages in thread
From: Marek Polacek @ 2017-06-23 15:05 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: GCC Patches, Jason Merrill, Joseph Myers

On Fri, Jun 23, 2017 at 04:48:33PM +0200, Jakub Jelinek wrote:
> On Fri, Jun 23, 2017 at 04:46:06PM +0200, Marek Polacek wrote:
> > +++ gcc/c-family/c-common.c
> > @@ -433,6 +433,8 @@ const struct c_common_resword c_common_reswords[] =
> >    { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 },
> >    { "__typeof",		RID_TYPEOF,	0 },
> >    { "__typeof__",	RID_TYPEOF,	0 },
> > +  { "__typeof_noqual",	RID_TYPEOF_NOQUAL, 0 },
> > +  { "__typeof_noqual__", RID_TYPEOF_NOQUAL, 0 },
> >    { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
> >    { "__volatile",	RID_VOLATILE,	0 },
> >    { "__volatile__",	RID_VOLATILE,	0 },
> > @@ -506,6 +508,7 @@ const struct c_common_resword c_common_reswords[] =
> >    { "typename",		RID_TYPENAME,	D_CXXONLY | D_CXXWARN },
> >    { "typeid",		RID_TYPEID,	D_CXXONLY | D_CXXWARN },
> >    { "typeof",		RID_TYPEOF,	D_ASM | D_EXT },
> > +  { "typeof_noqual",	RID_TYPEOF_NOQUAL, D_ASM | D_EXT },
> 
> Do you think we need this one?  Wouldn't just __typeof_noqual and
> __typeof_noqual__ be sufficient?

Unsure.  At first I didn't add typeof_noqual, but then I saw that our doc
use "typeof" and thought it might be better to be consistent and allow
typeof_noqual without leading underscores.  But in C++ it's only accepted
with -fgnu-keywords.

I could do without it.  Let's see what others think.

	Marek

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-23 14:46 C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985) Marek Polacek
  2017-06-23 14:48 ` Jakub Jelinek
@ 2017-06-23 16:28 ` Joseph Myers
  2017-06-26 15:09   ` Marek Polacek
  2017-06-26 16:37 ` Martin Sebor
  2 siblings, 1 reply; 22+ messages in thread
From: Joseph Myers @ 2017-06-23 16:28 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jason Merrill

On Fri, 23 Jun 2017, Marek Polacek wrote:

> You'll also see that I dropped all qualifiers for __auto_type.  But I actually
> couldn't trigger the
> init_type = c_build_qualified_type (init_type, TYPE_UNQUALIFIED);
> line in c_parser_declaration_or_fndef (even when running the whole testsuite)
> so I'm not convinced it makes any difference.

It looks like it would only make a difference, in the present code, for 
the case of an atomic register variable, or bit-field in an atomic 
structure, as the initializer.  Those are the cases where 
convert_lvalue_to_rvalue would not return a non-atomic result, given an 
atomic argument.  With the proposed change, it should apply to any 
qualified lvalue used as the initializer.

> @@ -506,6 +508,7 @@ const struct c_common_resword c_common_reswords[] =
>    { "typename",		RID_TYPENAME,	D_CXXONLY | D_CXXWARN },
>    { "typeid",		RID_TYPEID,	D_CXXONLY | D_CXXWARN },
>    { "typeof",		RID_TYPEOF,	D_ASM | D_EXT },
> +  { "typeof_noqual",	RID_TYPEOF_NOQUAL, D_ASM | D_EXT },
>    { "union",		RID_UNION,	0 },
>    { "unsigned",		RID_UNSIGNED,	0 },
>    { "using",		RID_USING,	D_CXXONLY | D_CXXWARN },

I don't think we should have this keyword variant.

I think there should be tests of the change to __auto_type.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-23 16:28 ` Joseph Myers
@ 2017-06-26 15:09   ` Marek Polacek
  0 siblings, 0 replies; 22+ messages in thread
From: Marek Polacek @ 2017-06-26 15:09 UTC (permalink / raw)
  To: Joseph Myers; +Cc: GCC Patches, Jason Merrill

On Fri, Jun 23, 2017 at 04:27:47PM +0000, Joseph Myers wrote:
> On Fri, 23 Jun 2017, Marek Polacek wrote:
> 
> > You'll also see that I dropped all qualifiers for __auto_type.  But I actually
> > couldn't trigger the
> > init_type = c_build_qualified_type (init_type, TYPE_UNQUALIFIED);
> > line in c_parser_declaration_or_fndef (even when running the whole testsuite)
> > so I'm not convinced it makes any difference.
> 
> It looks like it would only make a difference, in the present code, for 
> the case of an atomic register variable, or bit-field in an atomic 
> structure, as the initializer.  Those are the cases where 

Ah, right.  But since __auto_type doesn't work with bit-fields, I only
tested the register variant.

> convert_lvalue_to_rvalue would not return a non-atomic result, given an 
> atomic argument.  With the proposed change, it should apply to any 
> qualified lvalue used as the initializer.
 
Right.

> > @@ -506,6 +508,7 @@ const struct c_common_resword c_common_reswords[] =
> >    { "typename",		RID_TYPENAME,	D_CXXONLY | D_CXXWARN },
> >    { "typeid",		RID_TYPEID,	D_CXXONLY | D_CXXWARN },
> >    { "typeof",		RID_TYPEOF,	D_ASM | D_EXT },
> > +  { "typeof_noqual",	RID_TYPEOF_NOQUAL, D_ASM | D_EXT },
> >    { "union",		RID_UNION,	0 },
> >    { "unsigned",		RID_UNSIGNED,	0 },
> >    { "using",		RID_USING,	D_CXXONLY | D_CXXWARN },
> 
> I don't think we should have this keyword variant.

Ok, dropped.

> I think there should be tests of the change to __auto_type.

I've added one.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2017-06-26  Marek Polacek  <polacek@redhat.com>
	    Richard Henderson  <rth@redhat.com>

	PR c/65455
	PR c/39985
	* c-common.c (c_common_reswords): Add __typeof_noqual and
	__typeof_noqual__.
	(keyword_begins_type_specifier): Handle RID_TYPEOF_NOQUAL.
	* c-common.h (enum rid): Add RID_TYPEOF_NOQUAL.

	* c-parser.c (c_keyword_starts_typename): Handle RID_TYPEOF_NOQUAL.
	(c_token_starts_declspecs): Likewise.
	(c_parser_declaration_or_fndef): Always strip all qualifiers for
	__auto_type.
	(c_parser_declspecs): Handle RID_TYPEOF_NOQUAL.
	(c_parser_typeof_specifier): Handle RID_TYPEOF_NOQUAL by dropping
	all the qualifiers.
	(c_parser_objc_selector): Handle RID_TYPEOF_NOQUAL.

	* parser.c (cp_keyword_starts_decl_specifier_p): Handle RID_TYPEOF_NOQUAL.
	(cp_parser_simple_type_specifier): Handle RID_TYPEOF_NOQUAL by dropping
	all the qualifiers.

	* doc/extend.texi: Document __typeof_noqual.

	* c-c++-common/typeof-noqual-1.c: New test.
	* c-c++-common/typeof-noqual-2.c: New test.
	* gcc.dg/typeof-noqual-1.c: New test.
	* gcc.dg/auto-type-3.c: New test.

diff --git gcc/c-family/c-common.c gcc/c-family/c-common.c
index f6a9d05..7993de2 100644
--- gcc/c-family/c-common.c
+++ gcc/c-family/c-common.c
@@ -433,6 +433,8 @@ const struct c_common_resword c_common_reswords[] =
   { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 },
   { "__typeof",		RID_TYPEOF,	0 },
   { "__typeof__",	RID_TYPEOF,	0 },
+  { "__typeof_noqual",	RID_TYPEOF_NOQUAL, 0 },
+  { "__typeof_noqual__", RID_TYPEOF_NOQUAL, 0 },
   { "__underlying_type", RID_UNDERLYING_TYPE, D_CXXONLY },
   { "__volatile",	RID_VOLATILE,	0 },
   { "__volatile__",	RID_VOLATILE,	0 },
@@ -7511,6 +7513,7 @@ keyword_begins_type_specifier (enum rid keyword)
     case RID_SAT:
     case RID_COMPLEX:
     case RID_TYPEOF:
+    case RID_TYPEOF_NOQUAL:
     case RID_STRUCT:
     case RID_CLASS:
     case RID_UNION:
diff --git gcc/c-family/c-common.h gcc/c-family/c-common.h
index f3d051a..ad00ae8 100644
--- gcc/c-family/c-common.h
+++ gcc/c-family/c-common.h
@@ -100,8 +100,9 @@ enum rid
   /* C extensions */
   RID_ASM,       RID_TYPEOF,   RID_ALIGNOF,  RID_ATTRIBUTE,  RID_VA_ARG,
   RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_CHOOSE_EXPR,
-  RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,	     RID_BUILTIN_SHUFFLE,
-  RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
+  RID_TYPES_COMPATIBLE_P,      RID_BUILTIN_COMPLEX,
+  RID_BUILTIN_SHUFFLE, RID_DFLOAT32, RID_DFLOAT64,  RID_DFLOAT128,
+  RID_TYPEOF_NOQUAL,
 
   /* TS 18661-3 keywords, in the same sequence as the TI_* values.  */
   RID_FLOAT16,
diff --git gcc/c/c-parser.c gcc/c/c-parser.c
index f8fbc92..eb6cfad 100644
--- gcc/c/c-parser.c
+++ gcc/c/c-parser.c
@@ -495,6 +495,7 @@ c_keyword_starts_typename (enum rid keyword)
     case RID_STRUCT:
     case RID_UNION:
     case RID_TYPEOF:
+    case RID_TYPEOF_NOQUAL:
     case RID_CONST:
     case RID_ATOMIC:
     case RID_VOLATILE:
@@ -671,6 +672,7 @@ c_token_starts_declspecs (c_token *token)
 	case RID_STRUCT:
 	case RID_UNION:
 	case RID_TYPEOF:
+	case RID_TYPEOF_NOQUAL:
 	case RID_CONST:
 	case RID_VOLATILE:
 	case RID_RESTRICT:
@@ -1875,8 +1877,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
 			      " initializer");
 		  init = convert_lvalue_to_rvalue (init_loc, init, true, true);
 		  tree init_type = TREE_TYPE (init.value);
-		  /* As with typeof, remove all qualifiers from atomic types.  */
-		  if (init_type != error_mark_node && TYPE_ATOMIC (init_type))
+		  /* As with __typeof_noqual, remove all qualifiers.  */
+		  if (init_type != error_mark_node)
 		    init_type
 		      = c_build_qualified_type (init_type, TYPE_UNQUALIFIED);
 		  bool vm_type = variably_modified_type_p (init_type,
@@ -2557,6 +2559,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	  declspecs_add_type (loc, specs, t);
 	  break;
 	case RID_TYPEOF:
+	case RID_TYPEOF_NOQUAL:
 	  /* ??? The old parser rejected typeof after other type
 	     specifiers, but is a syntax error the best way of
 	     handling this?  */
@@ -3220,7 +3223,10 @@ c_parser_typeof_specifier (c_parser *parser)
   ret.spec = error_mark_node;
   ret.expr = NULL_TREE;
   ret.expr_const_operands = true;
-  gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
+
+  enum rid keyword = c_parser_peek_token (parser)->keyword;
+  gcc_assert (keyword == RID_TYPEOF || keyword == RID_TYPEOF_NOQUAL);
+
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
   in_typeof++;
@@ -3262,7 +3268,9 @@ c_parser_typeof_specifier (c_parser *parser)
       /* For use in macros such as those in <stdatomic.h>, remove all
 	 qualifiers from atomic types.  (const can be an issue for more macros
 	 using typeof than just the <stdatomic.h> ones.)  */
-      if (ret.spec != error_mark_node && TYPE_ATOMIC (ret.spec))
+      if (ret.spec != error_mark_node
+	  /* __typeof_noqual also drops the qualifiers.  */
+	  && (TYPE_ATOMIC (ret.spec) || keyword == RID_TYPEOF_NOQUAL))
 	ret.spec = c_build_qualified_type (ret.spec, TYPE_UNQUALIFIED);
     }
   c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
@@ -9746,6 +9754,7 @@ c_parser_objc_selector (c_parser *parser)
     case RID_ASM:
     case RID_SIZEOF:
     case RID_TYPEOF:
+    case RID_TYPEOF_NOQUAL:
     case RID_ALIGNOF:
     case RID_UNSIGNED:
     case RID_LONG:
diff --git gcc/cp/parser.c gcc/cp/parser.c
index c405fe5..79aae2a 100644
--- gcc/cp/parser.c
+++ gcc/cp/parser.c
@@ -976,6 +976,7 @@ cp_keyword_starts_decl_specifier_p (enum rid keyword)
       /* GNU extensions.  */ 
     case RID_ATTRIBUTE:
     case RID_TYPEOF:
+    case RID_TYPEOF_NOQUAL:
       /* C++0x extensions.  */
     case RID_DECLTYPE:
     case RID_UNDERLYING_TYPE:
@@ -16867,6 +16868,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       break;
 
     case RID_TYPEOF:
+    case RID_TYPEOF_NOQUAL:
       /* Consume the `typeof' token.  */
       cp_lexer_consume_token (parser->lexer);
       /* Parse the operand to `typeof'.  */
@@ -16874,6 +16876,9 @@ cp_parser_simple_type_specifier (cp_parser* parser,
       /* If it is not already a TYPE, take its type.  */
       if (!TYPE_P (type))
 	type = finish_typeof (type);
+      /* If requested, make the type unqualified.  */
+      if (token->keyword == RID_TYPEOF_NOQUAL && type != error_mark_node)
+	type = cp_build_qualified_type (type, TYPE_UNQUALIFIED);
 
       if (decl_specs)
 	cp_parser_set_decl_spec_type (decl_specs, type,
diff --git gcc/doc/extend.texi gcc/doc/extend.texi
index 43f9ecf..acfd7e8 100644
--- gcc/doc/extend.texi
+++ gcc/doc/extend.texi
@@ -155,7 +155,8 @@ the value of an enumeration constant, the width of a bit-field, or
 the initial value of a static variable.
 
 If you don't know the type of the operand, you can still do this, but you
-must use @code{typeof} or @code{__auto_type} (@pxref{Typeof}).
+must use @code{typeof}, @code{__typeof_noqual}, or @code{__auto_type}
+(@pxref{Typeof}).
 
 In G++, the result value of a statement expression undergoes array and
 function pointer decay, and is returned by value to the enclosing
@@ -642,6 +643,7 @@ myopen (const char *path, int oflag, ...)
 @node Typeof
 @section Referring to a Type with @code{typeof}
 @findex typeof
+@findex __typeof_noqual
 @findex sizeof
 @cindex macros, types of arguments
 
@@ -694,6 +696,22 @@ arithmetic type and evaluates each of its arguments exactly once:
     _a > _b ? _a : _b; @})
 @end smallexample
 
+@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;				\
+  @})
+
+const int ci = 5;
+MAX (ci, 12);
+@end smallexample
+
 @cindex underscores in variables in macros
 @cindex @samp{_} in variables in macros
 @cindex local variables in macros
diff --git gcc/testsuite/c-c++-common/typeof-noqual-1.c gcc/testsuite/c-c++-common/typeof-noqual-1.c
index e69de29..455e51f 100644
--- gcc/testsuite/c-c++-common/typeof-noqual-1.c
+++ gcc/testsuite/c-c++-common/typeof-noqual-1.c
@@ -0,0 +1,42 @@
+/* PR c/65455 */
+/* { dg-do compile } */
+/* { dg-options "-pedantic-errors" } */
+
+void
+foo (void)
+{
+  int i = 0;
+  const int ci = 0;
+  volatile int vi = 0;
+
+  __typeof(i) *ip = 0;
+  __typeof(ci) *cip = 0;
+  __typeof(vi) *vip = 0;
+
+  __typeof_noqual(i) *nip = 0;
+  __typeof_noqual(ci) *ncip = 0;
+  __typeof_noqual(vi) *nvip = 0;
+
+  __typeof_noqual__(i) *nip2 = 0;
+  __typeof_noqual__(ci) *ncip2 = 0;
+  __typeof_noqual__(vi) *nvip2 = 0;
+
+  ip = cip;		/* { dg-error "assignment discards|invalid conversion" } */
+  ip = vip;		/* { dg-error "assignment discards|invalid conversion" } */
+
+  ip = nip;
+  ip = ncip;
+  ip = nvip;
+
+  ip = nip2;
+  ip = ncip2;
+  ip = nvip2;
+
+  ncip = cip;		/* { dg-error "assignment discards|invalid conversion" } */
+  nvip = vip;		/* { dg-error "assignment discards|invalid conversion" } */
+  ncip2 = cip;		/* { dg-error "assignment discards|invalid conversion" } */
+  nvip2 = vip;		/* { dg-error "assignment discards|invalid conversion" } */
+
+  nip = ip;
+  nip2 = ip;
+}
diff --git gcc/testsuite/c-c++-common/typeof-noqual-2.c gcc/testsuite/c-c++-common/typeof-noqual-2.c
index e69de29..1a27e44 100644
--- gcc/testsuite/c-c++-common/typeof-noqual-2.c
+++ gcc/testsuite/c-c++-common/typeof-noqual-2.c
@@ -0,0 +1,32 @@
+/* PR c/65455 */
+/* { dg-do compile } */
+
+const int g(void);
+
+#define MAX(__x, __y)			\
+  ({					\
+  __typeof_noqual(__x) __ret = __x;	\
+  if (__y > __ret) __ret = __y;		\
+    __ret;				\
+  })
+
+void
+fn (void)
+{
+  const int ci = 5;
+  __typeof_noqual (({ ci; })) n1;
+  __typeof_noqual (ci) n2;
+  __typeof (g ()) n4;
+  __typeof_noqual (g ()) n3;
+
+  typedef __typeof_noqual(ci) T;
+  T n5;
+
+  n1 = 5;
+  n2 = 5;
+  n3 = 5;
+  n4 = 5;
+  n5 = 5;
+
+  MAX (ci, 12);
+}
diff --git gcc/testsuite/gcc.dg/auto-type-3.c gcc/testsuite/gcc.dg/auto-type-3.c
index e69de29..79479c8 100644
--- gcc/testsuite/gcc.dg/auto-type-3.c
+++ gcc/testsuite/gcc.dg/auto-type-3.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct S
+{
+  int k;
+};
+
+void
+foo (void)
+{
+  _Atomic register const int a = 3;
+  const int b = 16;
+  const struct S s;
+  int *const c = 0;
+
+  __auto_type i = a;
+  i++;
+  __auto_type j = b;
+  j++;
+  __auto_type k = s.k;
+  k++;
+  __auto_type l = c;
+  l++;
+}
diff --git gcc/testsuite/gcc.dg/typeof-noqual-1.c gcc/testsuite/gcc.dg/typeof-noqual-1.c
index e69de29..ec72506 100644
--- gcc/testsuite/gcc.dg/typeof-noqual-1.c
+++ gcc/testsuite/gcc.dg/typeof-noqual-1.c
@@ -0,0 +1,23 @@
+/* PR c/65455 */
+/* { dg-do compile } */
+/* { dg-options "-Wrestrict" } */
+
+int *restrict t;
+
+void
+bar (__typeof_noqual (t) p, __typeof_noqual (t) q)
+{
+}
+
+void
+baz (__typeof (t) p, __typeof (t) q)
+{
+}
+
+void
+foo (void)
+{
+  int i = 42;
+  bar (&i, &i);
+  baz (&i, &i); /* { dg-warning "passing argument 1 to restrict-qualified parameter aliases" } */
+}

	Marek

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-23 14:46 C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985) Marek Polacek
  2017-06-23 14:48 ` Jakub Jelinek
  2017-06-23 16:28 ` Joseph Myers
@ 2017-06-26 16:37 ` Martin Sebor
  2017-06-27 13:14   ` Marek Polacek
  2 siblings, 1 reply; 22+ messages in thread
From: Martin Sebor @ 2017-06-26 16:37 UTC (permalink / raw)
  To: Marek Polacek, GCC Patches, Jason Merrill, Joseph Myers

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))

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).

> +@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).

Martin

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-26 16:37 ` Martin Sebor
@ 2017-06-27 13:14   ` Marek Polacek
  2017-06-27 17:15     ` Martin Sebor
  0 siblings, 1 reply; 22+ messages in thread
From: Marek Polacek @ 2017-06-27 13:14 UTC (permalink / raw)
  To: Martin Sebor; +Cc: GCC Patches, Jason Merrill, Joseph Myers

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.)

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".

> 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.

> > +@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).

	Marek

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-27 13:14   ` Marek Polacek
@ 2017-06-27 17:15     ` Martin Sebor
  2017-06-27 17:50       ` Joseph Myers
  2017-06-28 15:19       ` Martin Sebor
  0 siblings, 2 replies; 22+ messages in thread
From: Martin Sebor @ 2017-06-27 17:15 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jason Merrill, Joseph Myers

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-27 17:15     ` Martin Sebor
@ 2017-06-27 17:50       ` Joseph Myers
  2017-06-27 21:55         ` Martin Sebor
  2017-06-28 15:19       ` Martin Sebor
  1 sibling, 1 reply; 22+ messages in thread
From: Joseph Myers @ 2017-06-27 17:50 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Marek Polacek, GCC Patches, Jason Merrill

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.  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.

> 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.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-27 17:50       ` Joseph Myers
@ 2017-06-27 21:55         ` Martin Sebor
  2017-06-27 22:32           ` Joseph Myers
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Sebor @ 2017-06-27 21:55 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Marek Polacek, GCC Patches, Jason Merrill

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-27 21:55         ` Martin Sebor
@ 2017-06-27 22:32           ` Joseph Myers
  2017-06-28  3:58             ` Martin Sebor
  0 siblings, 1 reply; 22+ messages in thread
From: Joseph Myers @ 2017-06-27 22:32 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Marek Polacek, GCC Patches, Jason Merrill

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.

> 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.

> 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).

> 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").

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-27 22:32           ` Joseph Myers
@ 2017-06-28  3:58             ` Martin Sebor
  2017-06-28  9:19               ` Joseph Myers
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Sebor @ 2017-06-28  3:58 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Marek Polacek, GCC Patches, Jason Merrill

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

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-28  3:58             ` Martin Sebor
@ 2017-06-28  9:19               ` Joseph Myers
  2017-06-28 15:43                 ` Martin Sebor
  0 siblings, 1 reply; 22+ messages in thread
From: Joseph Myers @ 2017-06-28  9:19 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Marek Polacek, GCC Patches, Jason Merrill

On Wed, 28 Jun 2017, Martin Sebor wrote:

> > 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

My point is that users should not need to update their definitions every 
time another qualifier is invented.  Either you need the "remove 
qualifiers except" functionality in the language, or you need a 
*compiler-provided* header that defines "remove qualifiers except" 
operations for every combination of qualifiers in that version of the 
compiler (because "remove qualifiers except _Atomic" and "remove 
qualifiers except address spaces" cannot be composed into "remove 
qualifiers except _Atomic and address spaces, and "remove const, volatile, 
restrict and address spaces" is not something user code should need to 
hardcode when the intent is "remove qualifiers except _Atomic").

> adjustments, again if/when necessary.  This is the C++ approach;

C++ doesn't seem to add new qualifiers so much.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-27 17:15     ` Martin Sebor
  2017-06-27 17:50       ` Joseph Myers
@ 2017-06-28 15:19       ` Martin Sebor
  1 sibling, 0 replies; 22+ messages in thread
From: Martin Sebor @ 2017-06-28 15:19 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jason Merrill, Joseph Myers

>> 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.

On second thought, I agree that if __remove_const and _volatile
were provided then __remove_restrict should also be, if only for
completeness.

Martin

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-28  9:19               ` Joseph Myers
@ 2017-06-28 15:43                 ` Martin Sebor
  2017-06-28 16:09                   ` Joseph Myers
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Sebor @ 2017-06-28 15:43 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Marek Polacek, GCC Patches, Jason Merrill

On 06/28/2017 03:19 AM, Joseph Myers wrote:
> On Wed, 28 Jun 2017, Martin Sebor wrote:
>
>>> 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
>
> My point is that users should not need to update their definitions every
> time another qualifier is invented.  Either you need the "remove
> qualifiers except" functionality in the language, or you need a
> *compiler-provided* header

Yes, that's what I'm suggesting.  It could also be a macro defined
by the driver on the command line, to avoid having to #include
a header.   But providing it as a built-in, like the lower-level
primitives, as a convenience wrapper around them, would be fine
too.

> that defines "remove qualifiers except"
> operations for every combination of qualifiers in that version of the
> compiler (because "remove qualifiers except _Atomic" and "remove
> qualifiers except address spaces" cannot be composed into "remove
> qualifiers except _Atomic and address spaces, and "remove const, volatile,
> restrict and address spaces" is not something user code should need to
> hardcode when the intent is "remove qualifiers except _Atomic").

I'm not sure I understand what you're trying to say.  I thought
we agreed earlier that __typeof_noqual__ would remove all type
qualifiers.

If you are saying that there are qualifiers that may need to be
removed for some use cases but kept for others (I mentioned one:
removing one or the other qualifier from const _Atomic T*, but
not both) then that's exactly why I argue for providing lower-
level primitives targeted at each of the qualifiers separately.
Having __typeof_noqual__ remove some but not all qualifiers would
be surprising to say the least.

Martin

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-28 15:43                 ` Martin Sebor
@ 2017-06-28 16:09                   ` Joseph Myers
  2017-06-28 16:58                     ` Martin Sebor
  0 siblings, 1 reply; 22+ messages in thread
From: Joseph Myers @ 2017-06-28 16:09 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Marek Polacek, GCC Patches, Jason Merrill

On Wed, 28 Jun 2017, Martin Sebor wrote:

> > that defines "remove qualifiers except"
> > operations for every combination of qualifiers in that version of the
> > compiler (because "remove qualifiers except _Atomic" and "remove
> > qualifiers except address spaces" cannot be composed into "remove
> > qualifiers except _Atomic and address spaces, and "remove const, volatile,
> > restrict and address spaces" is not something user code should need to
> > hardcode when the intent is "remove qualifiers except _Atomic").
> 
> I'm not sure I understand what you're trying to say.  I thought
> we agreed earlier that __typeof_noqual__ would remove all type
> qualifiers.

Yes, it should.

What I'm saying is: if you provide an interface that enables users to 
write code that means "remove const" and will continue to mean exactly 
that with future GCC versions, even when those versions have additional 
qualifiers, you should also provide an interface that enables users to 
write code that means "remove all qualifiers except _Atomic and address 
spaces" (and likewise for any other combination) and will continue to mean 
exactly that with future GCC versions, even when those versions have 
additional qualifiers.  Allowing users to write "remove const, volatile 
and restrict" is *not* the same, as the meanings would diverge when future 
qualifiers are added.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-28 16:09                   ` Joseph Myers
@ 2017-06-28 16:58                     ` Martin Sebor
  2017-06-28 17:42                       ` Joseph Myers
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Sebor @ 2017-06-28 16:58 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Marek Polacek, GCC Patches, Jason Merrill

On 06/28/2017 10:09 AM, Joseph Myers wrote:
> On Wed, 28 Jun 2017, Martin Sebor wrote:
>
>>> that defines "remove qualifiers except"
>>> operations for every combination of qualifiers in that version of the
>>> compiler (because "remove qualifiers except _Atomic" and "remove
>>> qualifiers except address spaces" cannot be composed into "remove
>>> qualifiers except _Atomic and address spaces, and "remove const, volatile,
>>> restrict and address spaces" is not something user code should need to
>>> hardcode when the intent is "remove qualifiers except _Atomic").
>>
>> I'm not sure I understand what you're trying to say.  I thought
>> we agreed earlier that __typeof_noqual__ would remove all type
>> qualifiers.
>
> Yes, it should.
>
> What I'm saying is: if you provide an interface that enables users to
> write code that means "remove const" and will continue to mean exactly
> that with future GCC versions, even when those versions have additional
> qualifiers, you should also provide an interface that enables users to
> write code that means "remove all qualifiers except _Atomic and address
> spaces" (and likewise for any other combination) and will continue to mean
> exactly that with future GCC versions, even when those versions have
> additional qualifiers.  Allowing users to write "remove const, volatile
> and restrict" is *not* the same, as the meanings would diverge when future
> qualifiers are added.

I see.  That seems reasonable, though more advanced than what
I was envisioning (or what has been requested in either of the
two bugs in the subject).

I don't think there is an equivalent, dedicated trait in C++ to
do that either.  One would have to be composed of the lower-level
ones.  There also is no trait that would remove all type qualifiers
(including extensions), or even traits for querying extensions.
So (AFAIK) there is no way in C++ to do exactly what you described.
That of course doesn't mean that it doesn't make sense, just that
it's too advanced even for C++ despite its highly evolved support
for generic programming.  I would suggest that although providing
something like it would be nice, its absence shouldn't stand in
the way of defining the more limited interfaces first.

Martin

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-28 16:58                     ` Martin Sebor
@ 2017-06-28 17:42                       ` Joseph Myers
  2017-06-29  1:23                         ` Martin Sebor
  0 siblings, 1 reply; 22+ messages in thread
From: Joseph Myers @ 2017-06-28 17:42 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Marek Polacek, GCC Patches, Jason Merrill

On Wed, 28 Jun 2017, Martin Sebor wrote:

> I don't think there is an equivalent, dedicated trait in C++ to
> do that either.  One would have to be composed of the lower-level
> ones.  There also is no trait that would remove all type qualifiers
> (including extensions), or even traits for querying extensions.
> So (AFAIK) there is no way in C++ to do exactly what you described.
> That of course doesn't mean that it doesn't make sense, just that
> it's too advanced even for C++ despite its highly evolved support
> for generic programming.  I would suggest that although providing
> something like it would be nice, its absence shouldn't stand in
> the way of defining the more limited interfaces first.

Does (standard) C++ have any of restrict, _Atomic or address spaces, which 
are what indicate doing more than simply things for const and volatile?

The more limited interfaces could, of course, be __typeof_noqual in some 
form.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-28 17:42                       ` Joseph Myers
@ 2017-06-29  1:23                         ` Martin Sebor
  2017-06-29 15:56                           ` Joseph Myers
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Sebor @ 2017-06-29  1:23 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Marek Polacek, GCC Patches, Jason Merrill

On 06/28/2017 11:41 AM, Joseph Myers wrote:
> On Wed, 28 Jun 2017, Martin Sebor wrote:
>
>> I don't think there is an equivalent, dedicated trait in C++ to
>> do that either.  One would have to be composed of the lower-level
>> ones.  There also is no trait that would remove all type qualifiers
>> (including extensions), or even traits for querying extensions.
>> So (AFAIK) there is no way in C++ to do exactly what you described.
>> That of course doesn't mean that it doesn't make sense, just that
>> it's too advanced even for C++ despite its highly evolved support
>> for generic programming.  I would suggest that although providing
>> something like it would be nice, its absence shouldn't stand in
>> the way of defining the more limited interfaces first.
>
> Does (standard) C++ have any of restrict, _Atomic or address spaces, which
> are what indicate doing more than simply things for const and volatile?

No, C++ 17 still has just two qualifiers: const and volatile.
It has no equivalent of restrict, and its equivalent of _Atomic
is a library type (class template).

There's no API, standard or otherwise, for traits to manipulate
implementation-defined qualifiers.  But in C++, qualifiers are
easy to detect, add, and remove, so the absence of standard or
G++-specific traits doesn't prevent advanced users from rolling
their own.

>
> The more limited interfaces could, of course, be __typeof_noqual in some
> form.

Actually, despite what I've been arguing, I agree.  I've come
to realize that what makes me uneasy about it is its name: it
makes it sound like a special purpose flavor of __typeof__,
when it really is a general purpose __remove_qualifiers trait.
How does renaming it to something like that sound?

Martin

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-29  1:23                         ` Martin Sebor
@ 2017-06-29 15:56                           ` Joseph Myers
  2017-06-29 16:35                             ` Martin Sebor
  0 siblings, 1 reply; 22+ messages in thread
From: Joseph Myers @ 2017-06-29 15:56 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Marek Polacek, GCC Patches, Jason Merrill

On Wed, 28 Jun 2017, Martin Sebor wrote:

> > The more limited interfaces could, of course, be __typeof_noqual in some
> > form.
> 
> Actually, despite what I've been arguing, I agree.  I've come
> to realize that what makes me uneasy about it is its name: it
> makes it sound like a special purpose flavor of __typeof__,
> when it really is a general purpose __remove_qualifiers trait.
> How does renaming it to something like that sound?

__typeof__ makes clear that it returns a type, whether given a type or an 
expression.  Can __remove_qualifiers be applied to an expression, and, if 
so, what does it do - return a type, or return the result of converting 
the expression to the corresponding type with whatever qualifiers removed?

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-29 15:56                           ` Joseph Myers
@ 2017-06-29 16:35                             ` Martin Sebor
  2017-07-19 11:29                               ` Marek Polacek
  0 siblings, 1 reply; 22+ messages in thread
From: Martin Sebor @ 2017-06-29 16:35 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Marek Polacek, GCC Patches, Jason Merrill

On 06/29/2017 09:56 AM, Joseph Myers wrote:
> On Wed, 28 Jun 2017, Martin Sebor wrote:
>
>>> The more limited interfaces could, of course, be __typeof_noqual in some
>>> form.
>>
>> Actually, despite what I've been arguing, I agree.  I've come
>> to realize that what makes me uneasy about it is its name: it
>> makes it sound like a special purpose flavor of __typeof__,
>> when it really is a general purpose __remove_qualifiers trait.
>> How does renaming it to something like that sound?
>
> __typeof__ makes clear that it returns a type, whether given a type or an
> expression.  Can __remove_qualifiers be applied to an expression, and, if
> so, what does it do - return a type, or return the result of converting
> the expression to the corresponding type with whatever qualifiers removed?

The C++ traits primitives
(https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html) work on types,
not expressions, so I would suggest to have __remove_qualifiers (and
the related __remove_const et al., if they should be added) follow
the same approach.

Martin

PS There are at least a couple of traits on the list above that
would be useful in C as well (__is_enum and __is_union, and maybe
also __underlying_type).

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985)
  2017-06-29 16:35                             ` Martin Sebor
@ 2017-07-19 11:29                               ` Marek Polacek
  0 siblings, 0 replies; 22+ messages in thread
From: Marek Polacek @ 2017-07-19 11:29 UTC (permalink / raw)
  To: Martin Sebor; +Cc: Joseph Myers, GCC Patches, Jason Merrill

On Thu, Jun 29, 2017 at 10:35:26AM -0600, Martin Sebor wrote:
> On 06/29/2017 09:56 AM, Joseph Myers wrote:
> > On Wed, 28 Jun 2017, Martin Sebor wrote:
> > 
> > > > The more limited interfaces could, of course, be __typeof_noqual in some
> > > > form.
> > > 
> > > Actually, despite what I've been arguing, I agree.  I've come
> > > to realize that what makes me uneasy about it is its name: it
> > > makes it sound like a special purpose flavor of __typeof__,
> > > when it really is a general purpose __remove_qualifiers trait.
> > > How does renaming it to something like that sound?
> > 
> > __typeof__ makes clear that it returns a type, whether given a type or an
> > expression.  Can __remove_qualifiers be applied to an expression, and, if
> > so, what does it do - return a type, or return the result of converting
> > the expression to the corresponding type with whatever qualifiers removed?

Sorry it's taken so long to respond.

> The C++ traits primitives
> (https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html) work on types,
> not expressions, so I would suggest to have __remove_qualifiers (and
> the related __remove_const et al., if they should be added) follow
> the same approach.

OK, let's say __remove_qualifiers only works for type names.  So then to
accomodate PR65455 and others we'd suggest

const int a = 3;
__remove_qualifiers (__typeof__(a)) x;
?

If that's the case, then I'll write a patch that does just that.
Regarding __remove_qualifiers (types, expr) and__remove_qualifiers_except,
I'd rather not pursue as part of this patch.

> PS There are at least a couple of traits on the list above that
> would be useful in C as well (__is_enum and __is_union, and maybe
> also __underlying_type).

This could be fun, but what's the use case for C?  Generic programming?
Not familiar with that; would certainly appreciate some test cases before
I dive into that.

	Marek

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2017-07-19 11:29 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-23 14:46 C/C++ PATCH to add __typeof_noqual (PR c/65455, c/39985) Marek Polacek
2017-06-23 14:48 ` Jakub Jelinek
2017-06-23 15:05   ` Marek Polacek
2017-06-23 16:28 ` Joseph Myers
2017-06-26 15:09   ` Marek Polacek
2017-06-26 16:37 ` Martin Sebor
2017-06-27 13:14   ` Marek Polacek
2017-06-27 17:15     ` Martin Sebor
2017-06-27 17:50       ` Joseph Myers
2017-06-27 21:55         ` Martin Sebor
2017-06-27 22:32           ` Joseph Myers
2017-06-28  3:58             ` Martin Sebor
2017-06-28  9:19               ` Joseph Myers
2017-06-28 15:43                 ` Martin Sebor
2017-06-28 16:09                   ` Joseph Myers
2017-06-28 16:58                     ` Martin Sebor
2017-06-28 17:42                       ` Joseph Myers
2017-06-29  1:23                         ` Martin Sebor
2017-06-29 15:56                           ` Joseph Myers
2017-06-29 16:35                             ` Martin Sebor
2017-07-19 11:29                               ` Marek Polacek
2017-06-28 15:19       ` Martin Sebor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).