c, v2: Add __typeof_unqual__ and __typeof_unqual support

Message ID ZNUDMvNw/UldnN9d@tucnak
State Unresolved
Headers
Series c, v2: Add __typeof_unqual__ and __typeof_unqual support |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Jakub Jelinek Aug. 10, 2023, 3:33 p.m. UTC
  Hi!

I'd like to ping this patch.  Reposting it as the extend.texi hunk
didn't apply cleanly anymore.  Bootstrapped/regtested again on x86_64-linux
and i686-linux, ok for trunk?

On Mon, Jun 12, 2023 at 09:51:22PM +0200, Jakub Jelinek via Gcc-patches wrote:
> As I mentioned in my stdckdint.h mail, I think having __ prefixed
> keywords for the typeof_unqual keyword which can be used in earlier
> language modes can be useful, not all code can be switched to C23
> right away.
> 
> The following patch implements that.  It keeps the non-C23 behavior
> for it for the _Noreturn functions to stay compatible with how
> __typeof__ behaves.
> 
> I think we don't need it for C++, in C++ we have standard
> traits to remove qualifiers etc.

2023-08-10  Jakub Jelinek  <jakub@redhat.com>

gcc/
	* doc/extend.texi (Typeof): Document typeof_unqual
	and __typeof_unqual__.
gcc/c-family/
	* c-common.cc (c_common_reswords): Add __typeof_unqual
	and __typeof_unqual__ spellings of typeof_unqual.
gcc/c/
	* c-parser.cc (c_parser_typeof_specifier): Handle
	__typeof_unqual and __typeof_unqual__ as !is_std.
gcc/testsuite/
	* gcc.dg/c11-typeof-2.c: New test.
	* gcc.dg/c11-typeof-3.c: New test.
	* gcc.dg/gnu11-typeof-3.c: New test.
	* gcc.dg/gnu11-typeof-4.c: New test.



	Jakub
  

Comments

Joseph Myers Aug. 10, 2023, 10:24 p.m. UTC | #1
On Thu, 10 Aug 2023, Jakub Jelinek via Gcc-patches wrote:

> I'd like to ping this patch.  Reposting it as the extend.texi hunk
> didn't apply cleanly anymore.  Bootstrapped/regtested again on x86_64-linux
> and i686-linux, ok for trunk?

OK.
  

Patch

--- gcc/c-family/c-common.cc.jj	2023-05-20 15:31:09.070663296 +0200
+++ gcc/c-family/c-common.cc	2023-06-10 19:20:11.106910976 +0200
@@ -420,6 +420,8 @@  const struct c_common_resword c_common_r
   { "__transaction_cancel", RID_TRANSACTION_CANCEL, 0 },
   { "__typeof",		RID_TYPEOF,	0 },
   { "__typeof__",	RID_TYPEOF,	0 },
+  { "__typeof_unqual",	RID_TYPEOF_UNQUAL, D_CONLY },
+  { "__typeof_unqual__", RID_TYPEOF_UNQUAL, D_CONLY },
   { "__volatile",	RID_VOLATILE,	0 },
   { "__volatile__",	RID_VOLATILE,	0 },
   { "__GIMPLE",		RID_GIMPLE,	D_CONLY },
--- gcc/c/c-parser.cc.jj	2023-06-06 20:02:35.587211846 +0200
+++ gcc/c/c-parser.cc	2023-06-10 19:22:15.577205685 +0200
@@ -4126,7 +4126,8 @@  c_parser_typeof_specifier (c_parser *par
     {
       gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF_UNQUAL));
       is_unqual = true;
-      is_std = true;
+      tree spelling = c_parser_peek_token (parser)->value;
+      is_std = strcmp (IDENTIFIER_POINTER (spelling), "typeof_unqual") == 0;
     }
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
--- gcc/doc/extend.texi.jj	2023-08-10 12:59:04.588094460 +0200
+++ gcc/doc/extend.texi	2023-08-10 13:00:09.301167471 +0200
@@ -843,6 +843,13 @@  Thus, @code{array (pointer (char), 4)} i
 pointers to @code{char}.
 @end itemize
 
+The ISO C2X operator @code{typeof_unqual} is available in ISO C2X mode
+and its result is the non-atomic unqualified version of what @code{typeof}
+operator returns.  Alternate spelling @code{__typeof_unqual__} is
+available in all C modes and provides non-atomic unqualified version of
+what @code{__typeof__} operator returns.
+@xref{Alternate Keywords}.
+
 @cindex @code{__auto_type} in GNU C
 In GNU C, but not GNU C++, you may also declare the type of a variable
 as @code{__auto_type}.  In that case, the declaration must declare
--- gcc/testsuite/gcc.dg/c11-typeof-2.c.jj	2023-06-10 19:27:38.675779747 +0200
+++ gcc/testsuite/gcc.dg/c11-typeof-2.c	2023-06-10 19:42:27.450606301 +0200
@@ -0,0 +1,177 @@ 
+/* Test GNU extensions __typeof__ and __typeof_unqual__.  Valid code.  */
+/* { dg-do run } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+int i;
+extern __typeof__ (i) i;
+extern __typeof (int) i;
+extern __typeof_unqual__ (i) i;
+extern __typeof_unqual (int) i;
+
+volatile int vi;
+extern __typeof__ (volatile int) vi;
+extern __typeof (vi) vi;
+
+extern __typeof_unqual__ (volatile int) i;
+extern __typeof_unqual__ (vi) i;
+extern __typeof__ ((const int) vi) i;
+extern __typeof ((volatile int) vi) i;
+
+const int ci;
+extern __typeof (const int) ci;
+extern __typeof (ci) ci;
+
+extern __typeof_unqual (const int) i;
+extern __typeof_unqual (ci) i;
+extern __typeof__ ((const int) ci) i;
+extern __typeof__ (+ci) i;
+extern __typeof (0, ci) i;
+extern __typeof__ (1 ? ci : ci) i;
+extern __typeof (0) i;
+
+const int fci (void);
+extern __typeof__ (fci ()) i;
+
+_Atomic int ai;
+extern __typeof (_Atomic int) ai;
+extern __typeof__ (_Atomic (int)) ai;
+extern __typeof (ai) ai;
+
+extern __typeof_unqual__ (_Atomic int) i;
+extern __typeof_unqual (_Atomic (int)) i;
+extern __typeof_unqual__ (ai) i;
+extern __typeof (+ai) i;
+extern __typeof__ ((_Atomic int) ai) i;
+extern __typeof__ (0, ai) i;
+extern __typeof (1 ? ai : ai) i;
+
+_Atomic int fai (void);
+extern __typeof__ (fai ()) i;
+
+_Atomic const volatile int acvi;
+extern __typeof (int volatile const _Atomic) acvi;
+extern __typeof (acvi) acvi;
+extern const _Atomic volatile __typeof (acvi) acvi;
+extern _Atomic volatile __typeof__ (ci) acvi;
+extern _Atomic const __typeof (vi) acvi;
+extern const __typeof__ (ai) volatile acvi;
+
+extern __typeof_unqual (acvi) i;
+extern __typeof_unqual__ (__typeof (acvi)) i;
+extern __typeof_unqual (_Atomic __typeof_unqual__ (acvi)) i;
+
+extern _Atomic __typeof_unqual (acvi) ai;
+
+char c;
+volatile char vc;
+volatile char *pvc;
+volatile char *const cpvc;
+const char *pcc;
+const char *volatile vpcc;
+__typeof (*vpcc) cc;
+
+extern __typeof__ (*cpvc) vc;
+extern __typeof_unqual (*cpvc) c;
+extern __typeof_unqual__ (cpvc) pvc;
+extern __typeof_unqual__ (vpcc) pcc;
+extern const char cc;
+
+extern __typeof (++vi) i;
+extern __typeof (++ai) i;
+extern __typeof__ (--vi) i;
+extern __typeof (--ai) i;
+extern __typeof__ (vi++) i;
+extern __typeof__ (ai++) i;
+extern __typeof (vi--) i;
+extern __typeof__ (ai--) i;
+
+_Bool b;
+volatile _Bool vb;
+_Atomic _Bool ab;
+extern __typeof__ (++vb) b;
+extern __typeof__ (++ab) b;
+extern __typeof (--vb) b;
+extern __typeof__ (--ab) b;
+extern __typeof (vb++) b;
+extern __typeof (ab++) b;
+extern __typeof__ (vb--) b;
+extern __typeof (ab--) b;
+
+extern __typeof__ (vc = 1) c;
+extern __typeof__ (vpcc = 0) pcc;
+extern __typeof (ai *= 2) i;
+
+int s = sizeof (__typeof__ (int (*)[++i]));
+
+void *vp;
+
+extern void abort (void);
+extern void exit (int);
+
+extern int only_used_in_typeof;
+
+static int not_defined (void);
+
+__typeof (i)
+main (__typeof (*vp))
+{
+  volatile __typeof__ (only_used_in_typeof) ii = 2;
+  if (ii != 2)
+    abort ();
+  const __typeof__ (not_defined ()) jj = 3;
+  if (jj != 3)
+    abort ();
+  unsigned int u = 1;
+  __typeof__ (u) u2 = 0;
+  __typeof (int (*)[++u2]) p = 0;
+  if (u2 != 1)
+    abort ();
+  if (sizeof (*p) != sizeof (int))
+    abort ();
+  __typeof_unqual (int (*)[++u2]) q = 0;
+  if (u2 != 2)
+    abort ();
+  if (sizeof (*q) != 2 * sizeof (int))
+    abort ();
+  if (sizeof (*p) != sizeof (int))
+    abort ();
+  __typeof (++u2) u3 = 1;
+  if (u2 != u + u3)
+    abort ();
+  __typeof_unqual__ (++u2) u4 = 2;
+  if (u2 != u4)
+    abort ();
+  u = sizeof (__typeof__ (int (*)[++u2]));
+  if (u2 != 2)
+    abort ();
+  u = sizeof (__typeof_unqual (int (*)[++u2]));
+  if (u2 != 2)
+    abort ();
+  __typeof ((int (*)[++u2]) 0) q2;
+  if (u2 != 3)
+    abort ();
+  __typeof ((void) 0, (int (*)[++u2]) 0) q3;
+  if (u2 != 4)
+    abort ();
+  __typeof__ ((int (*)[++u2]) 0, 0) q4;
+  if (u2 != 4)
+    abort ();
+  __typeof_unqual ((int (*)[++u2]) 0) q5;
+  if (u2 != 5)
+    abort ();
+  __typeof_unqual__ ((void) 0, (int (*)[++u2]) 0) q6;
+  if (u2 != 6)
+    abort ();
+  __typeof_unqual__ ((int (*)[++u2]) 0, 0) q7;
+  if (u2 != 6)
+    abort ();
+  int a1[6], a2[6];
+  int (*pa)[u2] = &a1;
+  __typeof (pa = &a2) pp;
+  if (pa != &a2)
+    abort ();
+  __typeof_unqual (pa = &a1) pp2;
+  if (pa != &a1)
+    abort ();
+  exit (0);
+}
--- gcc/testsuite/gcc.dg/c11-typeof-3.c.jj	2023-06-10 19:27:42.003734166 +0200
+++ gcc/testsuite/gcc.dg/c11-typeof-3.c	2023-06-10 19:46:38.041174992 +0200
@@ -0,0 +1,58 @@ 
+/* Test GNU extensions __typeof__ and __typeof_unqual__.  Invalid code.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+struct s { int i : 2; } x;
+union u { unsigned int j : 1; } y;
+
+__typeof__ (x.i) j; /* { dg-error "applied to a bit-field" } */
+__typeof_unqual__ (x.i) j2; /* { dg-error "applied to a bit-field" } */
+__typeof (y.j) j3; /* { dg-error "applied to a bit-field" } */
+__typeof_unqual (y.j) j4; /* { dg-error "applied to a bit-field" } */
+
+static int ok (void);
+static int also_ok (void);
+static int not_defined (void); /* { dg-error "used but never defined" } */
+static int also_not_defined (void); /* { dg-error "used but never defined" } */
+
+_Noreturn void nf1 (void);
+__attribute__((noreturn)) void nf2 (void);
+void fg (void) {}
+__typeof__ (&nf1) pnf1 = fg; /* { dg-error "qualified function pointer from unqualified" } */
+__typeof (&nf2) pnf2 = fg; /* { dg-error "qualified function pointer from unqualified" } */
+extern void (*pnf1) (void); /* { dg-error "conflicting types for" } */
+extern void (*pnf2) (void); /* { dg-error "conflicting types for" } */
+extern __typeof (nf1) *pnf1; /* { dg-error "conflicting types for" } */
+extern __typeof (nf1) *pnf2; /* { dg-error "conflicting types for" } */
+extern __typeof__ (nf2) *pnf1; /* { dg-error "conflicting types for" } */
+extern __typeof__ (nf2) *pnf2; /* { dg-error "conflicting types for" } */
+__typeof (*&nf1) fg2, fg2a, fg2b; /* { dg-error "ISO C forbids qualified function types" } */
+__typeof__ (*&nf2) fg3, fg3a, fg3b; /* { dg-error "ISO C forbids qualified function types" } */
+__typeof (nf1) fg4, fg4a, fg4b;
+__typeof__ (nf2) fg5, fg5a, fg5b;
+
+extern void abort (void);
+
+void fg2 (void) {} /* { dg-error "conflicting type qualifiers for" } */
+_Noreturn void fg2a (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */
+__attribute__((noreturn)) void fg2b (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */
+void fg3 (void) {} /* { dg-error "conflicting type qualifiers for" } */
+_Noreturn void fg3a (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */
+__attribute__((noreturn)) void fg3b (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */
+void fg4 (void) {}
+_Noreturn void fg4a (void) { abort (); }
+__attribute__((noreturn)) void fg4b (void) { abort (); }
+void fg5 (void) {}
+_Noreturn void fg5a (void) { abort (); }
+__attribute__((noreturn)) void fg5b (void) { abort (); }
+
+void
+f (void)
+{
+  __typeof__ (ok ()) x = 2;
+  __typeof_unqual (also_ok ()) y = 2;
+  int a[2];
+  int (*p)[x] = &a;
+  __typeof (p + not_defined ()) q;
+  __typeof_unqual__ (p + also_not_defined ()) q2;
+}
--- gcc/testsuite/gcc.dg/gnu11-typeof-3.c.jj	2023-06-10 19:39:59.936626612 +0200
+++ gcc/testsuite/gcc.dg/gnu11-typeof-3.c	2023-06-10 19:47:32.861424347 +0200
@@ -0,0 +1,177 @@ 
+/* Test GNU extensions __typeof__ and __typeof_unqual__.  Valid code.  */
+/* { dg-do run } */
+/* { dg-options "-std=gnu11" } */
+
+int i;
+extern __typeof__ (i) i;
+extern __typeof (int) i;
+extern __typeof_unqual__ (i) i;
+extern __typeof_unqual (int) i;
+
+volatile int vi;
+extern __typeof__ (volatile int) vi;
+extern __typeof (vi) vi;
+
+extern __typeof_unqual__ (volatile int) i;
+extern __typeof_unqual__ (vi) i;
+extern __typeof__ ((const int) vi) i;
+extern __typeof ((volatile int) vi) i;
+
+const int ci;
+extern __typeof (const int) ci;
+extern __typeof (ci) ci;
+
+extern __typeof_unqual (const int) i;
+extern __typeof_unqual (ci) i;
+extern __typeof__ ((const int) ci) i;
+extern __typeof__ (+ci) i;
+extern __typeof (0, ci) i;
+extern __typeof__ (1 ? ci : ci) i;
+extern __typeof (0) i;
+
+const int fci (void);
+extern __typeof__ (fci ()) i;
+
+_Atomic int ai;
+extern __typeof (_Atomic int) ai;
+extern __typeof__ (_Atomic (int)) ai;
+extern __typeof (ai) ai;
+
+extern __typeof_unqual__ (_Atomic int) i;
+extern __typeof_unqual (_Atomic (int)) i;
+extern __typeof_unqual__ (ai) i;
+extern __typeof (+ai) i;
+extern __typeof__ ((_Atomic int) ai) i;
+extern __typeof__ (0, ai) i;
+extern __typeof (1 ? ai : ai) i;
+
+_Atomic int fai (void);
+extern __typeof__ (fai ()) i;
+
+_Atomic const volatile int acvi;
+extern __typeof (int volatile const _Atomic) acvi;
+extern __typeof (acvi) acvi;
+extern const _Atomic volatile __typeof (acvi) acvi;
+extern _Atomic volatile __typeof__ (ci) acvi;
+extern _Atomic const __typeof (vi) acvi;
+extern const __typeof__ (ai) volatile acvi;
+
+extern __typeof_unqual (acvi) i;
+extern __typeof_unqual__ (__typeof (acvi)) i;
+extern __typeof_unqual (_Atomic __typeof_unqual__ (acvi)) i;
+
+extern _Atomic __typeof_unqual (acvi) ai;
+
+char c;
+volatile char vc;
+volatile char *pvc;
+volatile char *const cpvc;
+const char *pcc;
+const char *volatile vpcc;
+__typeof (*vpcc) cc;
+
+extern __typeof__ (*cpvc) vc;
+extern __typeof_unqual (*cpvc) c;
+extern __typeof_unqual__ (cpvc) pvc;
+extern __typeof_unqual__ (vpcc) pcc;
+extern const char cc;
+
+extern __typeof (++vi) i;
+extern __typeof (++ai) i;
+extern __typeof__ (--vi) i;
+extern __typeof (--ai) i;
+extern __typeof__ (vi++) i;
+extern __typeof__ (ai++) i;
+extern __typeof (vi--) i;
+extern __typeof__ (ai--) i;
+
+_Bool b;
+volatile _Bool vb;
+_Atomic _Bool ab;
+extern __typeof__ (++vb) b;
+extern __typeof__ (++ab) b;
+extern __typeof (--vb) b;
+extern __typeof__ (--ab) b;
+extern __typeof (vb++) b;
+extern __typeof (ab++) b;
+extern __typeof__ (vb--) b;
+extern __typeof (ab--) b;
+
+extern __typeof__ (vc = 1) c;
+extern __typeof__ (vpcc = 0) pcc;
+extern __typeof (ai *= 2) i;
+
+int s = sizeof (__typeof__ (int (*)[++i]));
+
+void *vp;
+
+extern void abort (void);
+extern void exit (int);
+
+extern int only_used_in_typeof;
+
+static int not_defined (void);
+
+__typeof (i)
+main (__typeof (*vp))
+{
+  volatile __typeof__ (only_used_in_typeof) ii = 2;
+  if (ii != 2)
+    abort ();
+  const __typeof__ (not_defined ()) jj = 3;
+  if (jj != 3)
+    abort ();
+  unsigned int u = 1;
+  __typeof__ (u) u2 = 0;
+  __typeof (int (*)[++u2]) p = 0;
+  if (u2 != 1)
+    abort ();
+  if (sizeof (*p) != sizeof (int))
+    abort ();
+  __typeof_unqual (int (*)[++u2]) q = 0;
+  if (u2 != 2)
+    abort ();
+  if (sizeof (*q) != 2 * sizeof (int))
+    abort ();
+  if (sizeof (*p) != sizeof (int))
+    abort ();
+  __typeof (++u2) u3 = 1;
+  if (u2 != u + u3)
+    abort ();
+  __typeof_unqual__ (++u2) u4 = 2;
+  if (u2 != u4)
+    abort ();
+  u = sizeof (__typeof__ (int (*)[++u2]));
+  if (u2 != 2)
+    abort ();
+  u = sizeof (__typeof_unqual (int (*)[++u2]));
+  if (u2 != 2)
+    abort ();
+  __typeof ((int (*)[++u2]) 0) q2;
+  if (u2 != 3)
+    abort ();
+  __typeof ((void) 0, (int (*)[++u2]) 0) q3;
+  if (u2 != 4)
+    abort ();
+  __typeof__ ((int (*)[++u2]) 0, 0) q4;
+  if (u2 != 4)
+    abort ();
+  __typeof_unqual ((int (*)[++u2]) 0) q5;
+  if (u2 != 5)
+    abort ();
+  __typeof_unqual__ ((void) 0, (int (*)[++u2]) 0) q6;
+  if (u2 != 6)
+    abort ();
+  __typeof_unqual__ ((int (*)[++u2]) 0, 0) q7;
+  if (u2 != 6)
+    abort ();
+  int a1[6], a2[6];
+  int (*pa)[u2] = &a1;
+  __typeof (pa = &a2) pp;
+  if (pa != &a2)
+    abort ();
+  __typeof_unqual (pa = &a1) pp2;
+  if (pa != &a1)
+    abort ();
+  exit (0);
+}
--- gcc/testsuite/gcc.dg/gnu11-typeof-4.c.jj	2023-06-10 19:40:04.211568056 +0200
+++ gcc/testsuite/gcc.dg/gnu11-typeof-4.c	2023-06-10 19:50:07.819302529 +0200
@@ -0,0 +1,58 @@ 
+/* Test GNU extensions __typeof__ and __typeof_unqual__.  Invalid code.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu11" } */
+
+struct s { int i : 2; } x;
+union u { unsigned int j : 1; } y;
+
+__typeof__ (x.i) j; /* { dg-error "applied to a bit-field" } */
+__typeof_unqual__ (x.i) j2; /* { dg-error "applied to a bit-field" } */
+__typeof (y.j) j3; /* { dg-error "applied to a bit-field" } */
+__typeof_unqual (y.j) j4; /* { dg-error "applied to a bit-field" } */
+
+static int ok (void);
+static int also_ok (void);
+static int not_defined (void); /* { dg-warning "used but never defined" } */
+static int also_not_defined (void); /* { dg-warning "used but never defined" } */
+
+_Noreturn void nf1 (void);
+__attribute__((noreturn)) void nf2 (void);
+void fg (void) {}
+__typeof__ (&nf1) pnf1 = fg; /* { dg-warning "qualified function pointer from unqualified" } */
+__typeof (&nf2) pnf2 = fg; /* { dg-warning "qualified function pointer from unqualified" } */
+extern void (*pnf1) (void); /* { dg-error "conflicting types for" } */
+extern void (*pnf2) (void); /* { dg-error "conflicting types for" } */
+extern __typeof (nf1) *pnf1; /* { dg-error "conflicting types for" } */
+extern __typeof (nf1) *pnf2; /* { dg-error "conflicting types for" } */
+extern __typeof__ (nf2) *pnf1; /* { dg-error "conflicting types for" } */
+extern __typeof__ (nf2) *pnf2; /* { dg-error "conflicting types for" } */
+__typeof (*&nf1) fg2, fg2a, fg2b;
+__typeof__ (*&nf2) fg3, fg3a, fg3b;
+__typeof (nf1) fg4, fg4a, fg4b;
+__typeof__ (nf2) fg5, fg5a, fg5b;
+
+extern void abort (void);
+
+void fg2 (void) {} /* { dg-error "conflicting type qualifiers for" } */
+_Noreturn void fg2a (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */
+__attribute__((noreturn)) void fg2b (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */
+void fg3 (void) {} /* { dg-error "conflicting type qualifiers for" } */
+_Noreturn void fg3a (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */
+__attribute__((noreturn)) void fg3b (void) { abort (); } /* { dg-error "conflicting type qualifiers for" } */
+void fg4 (void) {}
+_Noreturn void fg4a (void) { abort (); }
+__attribute__((noreturn)) void fg4b (void) { abort (); }
+void fg5 (void) {}
+_Noreturn void fg5a (void) { abort (); }
+__attribute__((noreturn)) void fg5b (void) { abort (); }
+
+void
+f (void)
+{
+  __typeof__ (ok ()) x = 2;
+  __typeof_unqual (also_ok ()) y = 2;
+  int a[2];
+  int (*p)[x] = &a;
+  __typeof (p + not_defined ()) q;
+  __typeof_unqual__ (p + also_not_defined ()) q2;
+}