public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Richard Biener <richard.guenther@gmail.com>
To: Joseph Myers <joseph@codesourcery.com>
Cc: gcc-patches@gcc.gnu.org
Subject: Re: c: C2x typeof
Date: Thu, 6 Oct 2022 10:32:50 +0200	[thread overview]
Message-ID: <CAFiYyc1rZVmOi3CNxXjXbD3YQCnnd_6vbzoVwueFj8k9rND5dw@mail.gmail.com> (raw)
In-Reply-To: <alpine.DEB.2.22.394.2210060120550.917581@digraph.polyomino.org.uk>

On Thu, Oct 6, 2022 at 3:22 AM Joseph Myers <joseph@codesourcery.com> wrote:
>
> [C++ maintainers / global reviewers, note that there is a C++
> front-end change here needing review.]
>
> 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++ front-end changes)?

I think those are obvious, but OK.

Thanks,
Richard.

>
> 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 --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 f6a94ba31d8..35fe6b4da81 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:
> @@ -3028,6 +3032,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?  */
> @@ -3715,22 +3720,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++;
> @@ -3772,6 +3793,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;
>  }
>
> @@ -11866,7 +11905,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
> @@ -11906,6 +11945,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;
> +}
>
> --
> Joseph S. Myers
> joseph@codesourcery.com

      reply	other threads:[~2022-10-06  8:33 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-06  1:21 Joseph Myers
2022-10-06  8:32 ` Richard Biener [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAFiYyc1rZVmOi3CNxXjXbD3YQCnnd_6vbzoVwueFj8k9rND5dw@mail.gmail.com \
    --to=richard.guenther@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=joseph@codesourcery.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).