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