Message ID | alpine.DEB.2.22.394.2210060120550.917581@digraph.polyomino.org.uk |
---|---|
State | New |
Headers | show |
Series | c: C2x typeof | expand |
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
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; +}