From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ej1-x62b.google.com (mail-ej1-x62b.google.com [IPv6:2a00:1450:4864:20::62b]) by sourceware.org (Postfix) with ESMTPS id 8421E3857BA6 for ; Thu, 6 Oct 2022 08:33:04 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 8421E3857BA6 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ej1-x62b.google.com with SMTP id o21so2860114ejm.11 for ; Thu, 06 Oct 2022 01:33:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date; bh=PoMZl4043omQmQ1kHlWwOYmbj8aNRhkE7pAClZauAQE=; b=LYLNJdEc5oZYIUFkm0pqO7MUuMQQy0iJzV4HhWeubcniKmGgeaFFT8VclyqwCTvITM 9JGEwUvTbxnflQ5rNgzFRvoFhJYWUy1hlb4Adif/xwnqiEedHwWNR5M7VH9JCi/6i4y2 iUWBNrLAGORDY6bR6ctNCwz7T1CVJn6K4EBLspe0Y5F+4axHQ4/TAw501TjtljFT7RtD ecUIxOapj7SRqQZaYUAwTOyMsLWu49bofglrJCKqaxTjIWEwPwG9qc5s37uB+Z2sy7XW xUvTNSJgN22vTLOAnzYgXHayzxuCjNyb0mn1XMJNw7mtQDV8x24p793sQhT3+Y4tZTT2 oprg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date; bh=PoMZl4043omQmQ1kHlWwOYmbj8aNRhkE7pAClZauAQE=; b=O9XFnzxz0e+LI9SXYPAllqS76OURC4ApNCZkKtM5TlmGYHrhJ4jUIOumAM7AWPGvV5 FM4aeUqcGK58GxdaUDFe2HlPJKtYaK8FUZ0fPxXJHvpIzzcK9+LmMkUqtn0R16wBwDyc KGig6/D65pXyQ7Zm+o7KsvgCK5A3z0tQ1e9N5VjaPR4CEF7dHWmXhCphv6AWC9Mjgdsl 36QcZle99mle2H/sZtlvGseRiUfVUkD0UtdUB0FphIbnKW3Bcv1mkRJfaOJod71h6cUj 6AhB/euLDqlo2h4AXRzGQbeV+oE2VlhCJZMFw/GUI0fJTVtkL0bh0gBv38CJJABU+zbq 5Owg== X-Gm-Message-State: ACrzQf1P7noVi8n4c+UBJ2sNeM+YMAEQYyHuEvabxkz2KwpfYZVbGvcP Ow4WRXAQvAH0rg5fUgMWhhMpPVbJz5gnITLg2GHqsd/F X-Google-Smtp-Source: AMsMyM6clLwReG76ScHQ2TJKqYerJYoPgG+5/pp+MI/uUEeREjJq/bo28HjxwXaYXqC7oCkvtMkQFnCcmHsarpGQF5U= X-Received: by 2002:a17:906:5d0f:b0:78d:1bed:890f with SMTP id g15-20020a1709065d0f00b0078d1bed890fmr3046246ejt.594.1665045182983; Thu, 06 Oct 2022 01:33:02 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Richard Biener Date: Thu, 6 Oct 2022 10:32:50 +0200 Message-ID: Subject: Re: c: C2x typeof To: Joseph Myers Cc: gcc-patches@gcc.gnu.org Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-8.2 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,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 List-Id: On Thu, Oct 6, 2022 at 3:22 AM Joseph Myers 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 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; > +} > > -- > Joseph S. Myers > joseph@codesourcery.com