From patchwork Thu Oct 6 01:21:22 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Joseph Myers X-Patchwork-Id: 1686555 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4MjYZ91Qx2z20Vp for ; Thu, 6 Oct 2022 12:21:51 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 12973384D153 for ; Thu, 6 Oct 2022 01:21:49 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from esa4.mentor.iphmx.com (esa4.mentor.iphmx.com [68.232.137.252]) by sourceware.org (Postfix) with ESMTPS id A0C793853835 for ; Thu, 6 Oct 2022 01:21:33 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org A0C793853835 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=codesourcery.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mentor.com X-IronPort-AV: E=Sophos;i="5.95,162,1661846400"; d="scan'208";a="84183292" Received: from orw-gwy-02-in.mentorg.com ([192.94.38.167]) by esa4.mentor.iphmx.com with ESMTP; 05 Oct 2022 17:21:31 -0800 IronPort-SDR: IA389yA1bc172UjjmV0+Z1O5hVmb3+Rx7kmDxFQBCH4BF8RzmDx3Ga0LGH2YgMHI/6ehiVL/e+ FYH1wS3Xk1vwEID0JWc5ca9rSMjSJfhCypEV4LNzIyGIClFxeoXRezIe/HwuFVNqILUrkAlgQz /ANk+X3GNQiqjMEFaT1pRgZ/exiQw9gHndUn0ybbdq/62U86/Vifxj2Jk10MIpMp9pbuuTtc1S 2YEq5ZTqDo3NAYaYZ+TsTtB+k6Qe3z3usFLWkXGVnJFxODXcLjOgNUP2zsAyVkHxNM9GuM/pQQ Vrw= Date: Thu, 6 Oct 2022 01:21:22 +0000 From: Joseph Myers X-X-Sender: jsm28@digraph.polyomino.org.uk To: Subject: c: C2x typeof Message-ID: User-Agent: Alpine 2.22 (DEB 394 2020-01-19) MIME-Version: 1.0 X-Originating-IP: [137.202.0.90] X-ClientProxiedBy: svr-ies-mbx-15.mgc.mentorg.com (139.181.222.15) To svr-ies-mbx-10.mgc.mentorg.com (139.181.222.10) X-Spam-Status: No, score=-3116.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, HEADER_FROM_DIFFERENT_DOMAINS, KAM_DMARC_STATUS, SPF_HELO_PASS, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" [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)? 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 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 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 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; +}