public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc r13-3135] c: C2x typeof
@ 2022-10-06 14:27 Joseph Myers
  0 siblings, 0 replies; only message in thread
From: Joseph Myers @ 2022-10-06 14:27 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:fa258f6894801aef6785f0327594dc803da63fbd

commit r13-3135-gfa258f6894801aef6785f0327594dc803da63fbd
Author: Joseph Myers <joseph@codesourcery.com>
Date:   Thu Oct 6 14:26:21 2022 +0000

    c: C2x typeof
    
    C2x adds typeof as a standard feature.  In general this follows
    existing GNU C semantics very closely, but there are various ways in
    which the implementation involves more than simply enabling the
    keyword for C2x:
    
    * As well as typeof, there is a typeof_unqual variant, which removes
      all qualifiers and _Atomic from the resulting type (whereas typeof
      preserves qualifiers and _Atomic on qualified or atomic (lvalue or
      type name) operands).
    
    * The typeof keyword is disabled by -fno-asm, so enabling it for C2x
      needs to be implemented in a way that preserves the disabling by
      -fno-asm for older standard versions (which having -fno-asm having
      no effect on it in C2x mode).  This is done via adding a new D_EXT11
      mask (which is also where the C++ front-end change comes from, to
      handle D_EXT11 appropriately there for -fno-asm and
      -fno-gnu-keywords).
    
    * GNU typeof treats the noreturn property of a function (as specified
      in standard C with _Noreturn or [[noreturn]]) as being part of the
      type of a pointer to function, but it is not part of the type in
      standard terms.  Thus a special case is needed in the typeof
      implementation, just like in the _Generic implementation, to avoid
      treating it as a type for standard typeof.  It seems plausible this
      is being used when copying the type of one object to another using
      typeof, so the existing semantics are preserved for __typeof__, and
      for typeof in pre-C2x modes, while typeof for C2x or later has the
      standard semantics.
    
    * It turns out that, even after Martin Uecker's changes in this area,
      there were still cases where rvalues could wrongly have a qualified
      or atomic type in GCC.  This applied to ++ and -- increment and
      decrement expressions, and also to calls to functions returning an
      atomic type.  (For the latter, the working draft doesn't actually
      explicitly exclude the function call expression having an atomic
      type, but given all the changes that have gone into C17 and C2x to
      avoid rvalues ever having qualified types, and given that
      lvalue-to-rvalue conversion removes both qualifiers and _Atomic, it
      seems unlikely that this (or casts, where GCC already removes
      _Atomic) is actually intended as a route to allow an
      _Atomic-qualified rvalue; I've noted this to raise as an NB comment
      on the CD ballot.)
    
    Bootstrapped with no regressions for x86_64-pc-linux-gnu.  OK to
    commit (C+
    
    gcc/
            * doc/invoke.texi (-fno-asm): Update description of effects on
            typeof keyword.
    
    gcc/c-family/
            * c-common.cc (c_common_reswords): Mark typeof as D_EXT11.  Add
            typeof_unqual.
            * c-common.h (enum rid): Add RID_TYPEOF_UNQUAL.
            (D_EXT11): New macro.  Values of subsequent macros updated.
    
    gcc/c/
            * c-parser.cc (c_parse_init): Add D_EXT11 to mask if flag_no_asm
            and not C2x.
            (c_keyword_starts_typename, c_token_starts_declspecs)
            (c_parser_declspecs, c_parser_objc_selector): Handle
            RID_TYPEOF_UNQUAL.
            (c_parser_typeof_specifier): Handle RID_TYPEOF_UNQUAL.
            Distinguish typeof for C2x from __typeof__ for all standard
            versions and typeof before C2x.
            * c-typeck.cc (build_function_call_vec): Use unqualified version
            of non-void return type.
            (build_unary_op): Use unqualified type for increment and
            decrement.
    
    gcc/cp/
            * lex.cc (init_reswords): Handle D_EXT11.
    
    gcc/testsuite/
            * gcc.dg/c11-typeof-1.c, gcc.dg/c2x-typeof-1.c,
            gcc.dg/c2x-typeof-2.c, gcc.dg/c2x-typeof-3.c,
            gcc.dg/gnu11-typeof-1.c, gcc.dg/gnu11-typeof-2.c,
            gcc.dg/gnu2x-typeof-1.c: New tests.

Diff:
---
 gcc/c-family/c-common.cc              |   3 +-
 gcc/c-family/c-common.h               |  24 ++--
 gcc/c/c-parser.cc                     |  46 +++++++-
 gcc/c/c-typeck.cc                     |  15 ++-
 gcc/cp/lex.cc                         |   4 +-
 gcc/doc/invoke.texi                   |   5 +-
 gcc/testsuite/gcc.dg/c11-typeof-1.c   |   6 +
 gcc/testsuite/gcc.dg/c2x-typeof-1.c   | 208 ++++++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/c2x-typeof-2.c   |  27 +++++
 gcc/testsuite/gcc.dg/c2x-typeof-3.c   |   7 ++
 gcc/testsuite/gcc.dg/gnu11-typeof-1.c |   6 +
 gcc/testsuite/gcc.dg/gnu11-typeof-2.c |  39 +++++++
 gcc/testsuite/gcc.dg/gnu2x-typeof-1.c |  39 +++++++
 13 files changed, 406 insertions(+), 23 deletions(-)

diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 4f9878d2695..ffe17eaa9d9 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -494,7 +494,8 @@ const struct c_common_resword c_common_reswords[] =
   { "typedef",		RID_TYPEDEF,	0 },
   { "typename",		RID_TYPENAME,	D_CXXONLY | D_CXXWARN },
   { "typeid",		RID_TYPEID,	D_CXXONLY | D_CXXWARN },
-  { "typeof",		RID_TYPEOF,	D_ASM | D_EXT },
+  { "typeof",		RID_TYPEOF,	D_EXT11 },
+  { "typeof_unqual",	RID_TYPEOF_UNQUAL,	D_CONLY | D_C2X },
   { "union",		RID_UNION,	0 },
   { "unsigned",		RID_UNSIGNED,	0 },
   { "using",		RID_USING,	D_CXXONLY | D_CXXWARN },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 5f470d94f4a..62ab4ba437b 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -104,7 +104,8 @@ enum rid
   RID_SIZEOF,
 
   /* C extensions */
-  RID_ASM,       RID_TYPEOF,   RID_ALIGNOF,  RID_ATTRIBUTE,  RID_VA_ARG,
+  RID_ASM,       RID_TYPEOF,   RID_TYPEOF_UNQUAL, 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_BUILTIN_SHUFFLEVECTOR,   RID_BUILTIN_CONVERTVECTOR,   RID_BUILTIN_TGMATH,
@@ -438,16 +439,17 @@ extern machine_mode c_default_pointer_mode;
 #define D_CXX11         0x0010	/* In C++, C++11 only.  */
 #define D_EXT		0x0020	/* GCC extension.  */
 #define D_EXT89		0x0040	/* GCC extension incorporated in C99.  */
-#define D_ASM		0x0080	/* Disabled by -fno-asm.  */
-#define D_OBJC		0x0100	/* In Objective C and neither C nor C++.  */
-#define D_CXX_OBJC	0x0200	/* In Objective C, and C++, but not C.  */
-#define D_CXXWARN	0x0400	/* In C warn with -Wcxx-compat.  */
-#define D_CXX_CONCEPTS  0x0800	/* In C++, only with concepts.  */
-#define D_TRANSMEM	0x1000	/* C++ transactional memory TS.  */
-#define D_CXX_CHAR8_T	0x2000	/* In C++, only with -fchar8_t.  */
-#define D_CXX20		0x4000  /* In C++, C++20 only.  */
-#define D_CXX_COROUTINES 0x8000  /* In C++, only with coroutines.  */
-#define D_CXX_MODULES	0x10000  /* In C++, only with modules.  */
+#define D_EXT11		0x0080	/* GCC extension incorporated in C2X.  */
+#define D_ASM		0x0100	/* Disabled by -fno-asm.  */
+#define D_OBJC		0x0200	/* In Objective C and neither C nor C++.  */
+#define D_CXX_OBJC	0x0400	/* In Objective C, and C++, but not C.  */
+#define D_CXXWARN	0x0800	/* In C warn with -Wcxx-compat.  */
+#define D_CXX_CONCEPTS  0x1000	/* In C++, only with concepts.  */
+#define D_TRANSMEM	0x2000	/* C++ transactional memory TS.  */
+#define D_CXX_CHAR8_T	0x4000	/* In C++, only with -fchar8_t.  */
+#define D_CXX20		0x8000  /* In C++, C++20 only.  */
+#define D_CXX_COROUTINES 0x10000  /* In C++, only with coroutines.  */
+#define D_CXX_MODULES	0x20000  /* In C++, only with modules.  */
 
 #define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX_CONCEPTS
 #define D_CXX_CHAR8_T_FLAGS D_CXXONLY | D_CXX_CHAR8_T
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 67b919c0b18..89e05870f47 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -127,6 +127,8 @@ c_parse_init (void)
       mask |= D_ASM | D_EXT;
       if (!flag_isoc99)
 	mask |= D_EXT89;
+      if (!flag_isoc2x)
+	mask |= D_EXT11;
     }
   if (!c_dialect_objc ())
     mask |= D_OBJC | D_CXX_OBJC;
@@ -580,6 +582,7 @@ c_keyword_starts_typename (enum rid keyword)
     case RID_STRUCT:
     case RID_UNION:
     case RID_TYPEOF:
+    case RID_TYPEOF_UNQUAL:
     case RID_CONST:
     case RID_ATOMIC:
     case RID_VOLATILE:
@@ -757,6 +760,7 @@ c_token_starts_declspecs (c_token *token)
 	case RID_STRUCT:
 	case RID_UNION:
 	case RID_TYPEOF:
+	case RID_TYPEOF_UNQUAL:
 	case RID_CONST:
 	case RID_VOLATILE:
 	case RID_RESTRICT:
@@ -3081,6 +3085,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
 	  declspecs_add_type (loc, specs, t);
 	  break;
 	case RID_TYPEOF:
+	case RID_TYPEOF_UNQUAL:
 	  /* ??? The old parser rejected typeof after other type
 	     specifiers, but is a syntax error the best way of
 	     handling this?  */
@@ -3768,22 +3773,38 @@ c_parser_struct_declaration (c_parser *parser)
   return decls;
 }
 
-/* Parse a typeof specifier (a GNU extension).
+/* Parse a typeof specifier (a GNU extension adopted in C2X).
 
    typeof-specifier:
      typeof ( expression )
      typeof ( type-name )
+     typeof_unqual ( expression )
+     typeof_unqual ( type-name )
 */
 
 static struct c_typespec
 c_parser_typeof_specifier (c_parser *parser)
 {
+  bool is_unqual;
+  bool is_std;
   struct c_typespec ret;
   ret.kind = ctsk_typeof;
   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));
+  if (c_parser_next_token_is_keyword (parser, RID_TYPEOF))
+    {
+      is_unqual = false;
+      tree spelling = c_parser_peek_token (parser)->value;
+      is_std = (flag_isoc2x
+		&& strcmp (IDENTIFIER_POINTER (spelling), "typeof") == 0);
+    }
+  else
+    {
+      gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF_UNQUAL));
+      is_unqual = true;
+      is_std = true;
+    }
   c_parser_consume_token (parser);
   c_inhibit_evaluation_warnings++;
   in_typeof++;
@@ -3825,6 +3846,24 @@ c_parser_typeof_specifier (c_parser *parser)
       pop_maybe_used (was_vm);
     }
   parens.skip_until_found_close (parser);
+  if (ret.spec != error_mark_node)
+    {
+      if (is_unqual && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED)
+	ret.spec = TYPE_MAIN_VARIANT (ret.spec);
+      if (is_std)
+	{
+	  /* In ISO C terms, _Noreturn is not part of the type of
+	     expressions such as &abort, but in GCC it is represented
+	     internally as a type qualifier.  */
+	  if (TREE_CODE (ret.spec) == FUNCTION_TYPE
+	      && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED)
+	    ret.spec = TYPE_MAIN_VARIANT (ret.spec);
+	  else if (FUNCTION_POINTER_TYPE_P (ret.spec)
+		   && TYPE_QUALS (TREE_TYPE (ret.spec)) != TYPE_UNQUALIFIED)
+	    ret.spec
+	      = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (ret.spec)));
+	}
+    }
   return ret;
 }
 
@@ -11961,7 +12000,7 @@ c_parser_objc_synchronized_statement (c_parser *parser)
      identifier
      one of
        enum struct union if else while do for switch case default
-       break continue return goto asm sizeof typeof __alignof
+       break continue return goto asm sizeof typeof typeof_unqual __alignof
        unsigned long const short volatile signed restrict _Complex
        in out inout bycopy byref oneway int char float double void _Bool
        _Atomic
@@ -12001,6 +12040,7 @@ c_parser_objc_selector (c_parser *parser)
     case RID_ASM:
     case RID_SIZEOF:
     case RID_TYPEOF:
+    case RID_TYPEOF_UNQUAL:
     case RID_ALIGNOF:
     case RID_UNSIGNED:
     case RID_LONG:
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index ac242b5ed13..f9190680a3c 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3187,6 +3187,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
 
   /* fntype now gets the type of function pointed to.  */
   fntype = TREE_TYPE (fntype);
+  tree return_type = TREE_TYPE (fntype);
 
   /* Convert the parameters to the types declared in the
      function prototype, or apply default promotions.  */
@@ -3203,8 +3204,6 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
       && TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL
       && !comptypes (fntype, TREE_TYPE (tem)))
     {
-      tree return_type = TREE_TYPE (fntype);
-
       /* This situation leads to run-time undefined behavior.  We can't,
 	 therefore, simply error unless we can prove that all possible
 	 executions of the program must execute the code.  */
@@ -3229,22 +3228,25 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
   bool warned_p = check_function_arguments (loc, fundecl, fntype,
 					    nargs, argarray, &arg_loc);
 
+  if (TYPE_QUALS (return_type) != TYPE_UNQUALIFIED
+      && !VOID_TYPE_P (return_type))
+    return_type = c_build_qualified_type (return_type, TYPE_UNQUALIFIED);
   if (name != NULL_TREE
       && startswith (IDENTIFIER_POINTER (name), "__builtin_"))
     {
       if (require_constant_value)
 	result
-	  = fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype),
+	  = fold_build_call_array_initializer_loc (loc, return_type,
 						   function, nargs, argarray);
       else
-	result = fold_build_call_array_loc (loc, TREE_TYPE (fntype),
+	result = fold_build_call_array_loc (loc, return_type,
 					    function, nargs, argarray);
       if (TREE_CODE (result) == NOP_EXPR
 	  && TREE_CODE (TREE_OPERAND (result, 0)) == INTEGER_CST)
 	STRIP_TYPE_NOPS (result);
     }
   else
-    result = build_call_array_loc (loc, TREE_TYPE (fntype),
+    result = build_call_array_loc (loc, return_type,
 				   function, nargs, argarray);
   /* If -Wnonnull warning has been diagnosed, avoid diagnosing it again
      later.  */
@@ -4831,6 +4833,9 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
 	else
 	  val = build2 (code, TREE_TYPE (arg), arg, inc);
 	TREE_SIDE_EFFECTS (val) = 1;
+	if (TYPE_QUALS (TREE_TYPE (val)) != TYPE_UNQUALIFIED)
+	  TREE_TYPE (val) = c_build_qualified_type (TREE_TYPE (val),
+						    TYPE_UNQUALIFIED);
 	ret = val;
 	goto return_build_unary_op;
       }
diff --git a/gcc/cp/lex.cc b/gcc/cp/lex.cc
index 0b121a91e1c..22d1ab92add 100644
--- a/gcc/cp/lex.cc
+++ b/gcc/cp/lex.cc
@@ -241,9 +241,9 @@ init_reswords (void)
   if (!flag_char8_t)
     mask |= D_CXX_CHAR8_T;
   if (flag_no_asm)
-    mask |= D_ASM | D_EXT;
+    mask |= D_ASM | D_EXT | D_EXT11;
   if (flag_no_gnu_keywords)
-    mask |= D_EXT;
+    mask |= D_EXT | D_EXT11;
 
   /* The Objective-C keywords are all context-dependent.  */
   mask |= D_OBJC;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e0c2c57c9b2..a2b0b9636f0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -2534,7 +2534,10 @@ this switch.  You may want to use the @option{-fno-gnu-keywords} flag
 instead, which disables @code{typeof} but not @code{asm} and
 @code{inline}.  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.
+since @code{inline} is a standard keyword in ISO C99.  In C2X mode
+(@option{-std=c2x} or @option{-std=gnu2x}), this switch only affects
+the @code{asm} keyword, since @code{typeof} is a standard keyword in
+ISO C2X.
 
 @item -fno-builtin
 @itemx -fno-builtin-@var{function}
diff --git a/gcc/testsuite/gcc.dg/c11-typeof-1.c b/gcc/testsuite/gcc.dg/c11-typeof-1.c
new file mode 100644
index 00000000000..a2abe8e465c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-typeof-1.c
@@ -0,0 +1,6 @@
+/* Test typeof and typeof_unqual not keywords in C11.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+int typeof = 1;
+long typeof_unqual = 2;
diff --git a/gcc/testsuite/gcc.dg/c2x-typeof-1.c b/gcc/testsuite/gcc.dg/c2x-typeof-1.c
new file mode 100644
index 00000000000..0b721fedd4c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-typeof-1.c
@@ -0,0 +1,208 @@
+/* Test C2x typeof and typeof_unqual.  Valid code.  */
+/* { dg-do run } */
+/* { dg-options "-std=c2x -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;
+
+/* The non-returning property of a function is not part of the type given by
+   ISO C typeof.  */
+_Noreturn void nf1 (void);
+[[noreturn]] void nf2 (void);
+void fg (void) {}
+typeof (&nf1) pnf1 = fg;
+typeof (&nf2) pnf2 = fg;
+extern void (*pnf1) (void);
+extern void (*pnf2) (void);
+extern typeof (nf1) *pnf1;
+extern typeof (nf1) *pnf2;
+extern typeof (nf2) *pnf1;
+extern typeof (nf2) *pnf2;
+typeof (*&nf1) fg2, fg2a, fg2b;
+typeof (*&nf2) fg3, fg3a, fg3b;
+typeof (nf1) fg4, fg4a, fg4b;
+typeof (nf2) fg5, fg5a, fg5b;
+
+extern void abort (void);
+extern void exit (int);
+
+void fg2 (void) {}
+_Noreturn void fg2a (void) { abort (); }
+[[noreturn]] void fg2b (void) { abort (); }
+void fg3 (void) {}
+_Noreturn void fg3a (void) { abort (); }
+[[noreturn]] void fg3b (void) { abort (); }
+void fg4 (void) {}
+_Noreturn void fg4a (void) { abort (); }
+[[noreturn]] void fg4b (void) { abort (); }
+void fg5 (void) {}
+_Noreturn void fg5a (void) { abort (); }
+[[noreturn]] void fg5b (void) { abort (); }
+
+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);
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-typeof-2.c b/gcc/testsuite/gcc.dg/c2x-typeof-2.c
new file mode 100644
index 00000000000..f1c30a00a7f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-typeof-2.c
@@ -0,0 +1,27 @@
+/* Test C2x typeof and typeof_unqual.  Invalid code.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -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" } */
+
+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;
+}
diff --git a/gcc/testsuite/gcc.dg/c2x-typeof-3.c b/gcc/testsuite/gcc.dg/c2x-typeof-3.c
new file mode 100644
index 00000000000..c7a057700d3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c2x-typeof-3.c
@@ -0,0 +1,7 @@
+/* Test C2x typeof and typeof_unqual.  -fno-asm has no effect on keywords in
+   C2x mode.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors -fno-asm" } */
+
+int i;
+extern typeof (i) i;
diff --git a/gcc/testsuite/gcc.dg/gnu11-typeof-1.c b/gcc/testsuite/gcc.dg/gnu11-typeof-1.c
new file mode 100644
index 00000000000..6477c78bd37
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu11-typeof-1.c
@@ -0,0 +1,6 @@
+/* Test typeof and typeof_unqual not keywords with -std=gnu11 -fno-asm.  */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu11 -fno-asm" } */
+
+int typeof = 1;
+long typeof_unqual = 2;
diff --git a/gcc/testsuite/gcc.dg/gnu11-typeof-2.c b/gcc/testsuite/gcc.dg/gnu11-typeof-2.c
new file mode 100644
index 00000000000..e60ad466c37
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu11-typeof-2.c
@@ -0,0 +1,39 @@
+/* Test typeof propagation of noreturn function attributes with -std=gnu11:
+   these are part of the type of a function pointer with GNU typeof, but not
+   with C2x typeof.  */
+/* { dg-do link } */
+/* { dg-options "-std=gnu11 -O2" } */
+
+_Noreturn void f (void);
+
+typeof (&f) volatile p;
+typeof (&p) volatile pp;
+
+void link_failure (void);
+
+void
+g (void)
+{
+  (*p) ();
+  link_failure ();
+}
+
+void
+h (void)
+{
+  (**pp) ();
+  link_failure ();
+}
+
+volatile int flag;
+volatile int x;
+
+int
+main (void)
+{
+  if (flag)
+    g ();
+  if (flag)
+    h ();
+  return x;
+}
diff --git a/gcc/testsuite/gcc.dg/gnu2x-typeof-1.c b/gcc/testsuite/gcc.dg/gnu2x-typeof-1.c
new file mode 100644
index 00000000000..f14b54f1f7f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu2x-typeof-1.c
@@ -0,0 +1,39 @@
+/* Test __typeof__ propagation of noreturn function attributes with -std=gnu2x:
+   these are part of the type of a function pointer with GNU __typeof__, but
+   not with C2x typeof.  */
+/* { dg-do link } */
+/* { dg-options "-std=gnu2x -O2" } */
+
+_Noreturn void f (void);
+
+__typeof__ (&f) volatile p;
+__typeof__ (&p) volatile pp;
+
+void link_failure (void);
+
+void
+g (void)
+{
+  (*p) ();
+  link_failure ();
+}
+
+void
+h (void)
+{
+  (**pp) ();
+  link_failure ();
+}
+
+volatile int flag;
+volatile int x;
+
+int
+main (void)
+{
+  if (flag)
+    g ();
+  if (flag)
+    h ();
+  return x;
+}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2022-10-06 14:27 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-06 14:27 [gcc r13-3135] c: C2x typeof Joseph Myers

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