This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Add __auto_type C extension, use it in <stdatomic.h>
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: "Joseph S. Myers" <joseph at codesourcery dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Wed, 13 Nov 2013 11:39:00 +0100
- Subject: Re: Add __auto_type C extension, use it in <stdatomic.h>
- Authentication-results: sourceware.org; auth=none
- References: <Pine dot LNX dot 4 dot 64 dot 1311130038460 dot 6467 at digraph dot polyomino dot org dot uk>
On Wed, Nov 13, 2013 at 1:39 AM, Joseph S. Myers
<joseph@codesourcery.com> wrote:
> <stdatomic.h> contains what C11 describes as "generic functions".
> Although DR#419 makes clear that users cannot #undef these macros (or
> otherwise suppress use of a macro definition) and expect to find an
> underlying function, they still need to behave like functions as
> regards evaluating their arguments exactly once (see C11 7.1.4).
>
> I noted when adding <stdatomic.h> to mainline that some of the macro
> definitions there failed that requirement in the case where the
> pointer argument had variably modified type, because then typeof
> evaluates its argument and so that argument would be evaluated twice.
> Avoiding such double evaluation requires defining the type of a
> temporary variable, and initializing it with the pointer argument,
> with a single evaluation. To achieve this, this patch adds a new GNU
> C extension __auto_type, essentially a restricted version of C++11
> auto, and uses it in <stdatomic.h>.
I suppose you didn't use '__auto' because that's much more likely
used elsewhere than '__auto_type'?
Richard.
> As this is a generic issue for
> type-generic macros, if arguments of variably modified type are
> allowed, and as such a facility is useful anyway to ensure the
> argument text appears only once in the macro expansion and so avoid
> exponential blowup when calls to such macros appear in arguments to
> such macros, the extension is documented for general use.
>
> I'm not aware of any further architecture-independent issues with the
> C11 atomics support, though I'm sure some will be found as people
> start using it in practice (and architecture maintainers still need to
> add their TARGET_ATOMIC_ASSIGN_EXPAND_FENV definitions).
>
> Bootstrapped with no regressions on x86_64-unknown-linux-gnu. Applied
> to mainline.
>
> 2013-11-13 Joseph Myers <joseph@codesourcery.com>
>
> * doc/extend.texi (Statement Exprs, Typeof): Discuss __auto_type.
> * ginclude/stdatomic.h (kill_dependency, atomic_store_explicit)
> (atomic_load_explicit, atomic_exchange_explicit)
> (atomic_compare_exchange_strong_explicit)
> (atomic_compare_exchange_weak_explicit): Use __auto_type to
> declare variable initialized with PTR argument.
>
> c-family:
> 2013-11-13 Joseph Myers <joseph@codesourcery.com>
>
> * c-common.h (enum rid): Add RID_AUTO_TYPE.
> * c-common.c (c_common_reswords): Add __auto_type.
> (keyword_begins_type_specifier): Handle RID_AUTO_TYPE.
>
> c:
> 2013-11-13 Joseph Myers <joseph@codesourcery.com>
>
> * c-tree.h (c_typespec_keyword): Add cts_auto_type.
> * c-decl.c (declspecs_add_type, finish_declspecs): Handle
> __auto_type.
> * c-parser.c (c_token_starts_typename, c_token_starts_declspecs)
> (c_parser_attribute_any_word, c_parser_objc_selector): Handle
> RID_AUTO_TYPE.
> (c_parser_declspecs): Take argument AUTO_TYPE_OK.
> (c_parser_declaration_or_fndef, c_parser_struct_declaration)
> (c_parser_declarator, c_parser_direct_declarator_inner)
> (c_parser_parameter_declaration, c_parser_type_name): All callers
> changed.
> (c_parser_declaration_or_fndef): Handle declarations with type
> determined from the initializer.
>
> testsuite:
> 2013-11-13 Joseph Myers <joseph@codesourcery.com>
>
> * gcc.dg/atomic/stdatomic-vm.c, gcc.dg/auto-type-1.c,
> gcc.dg/auto-type-2.c: New tests.
>
> Index: gcc/ginclude/stdatomic.h
> ===================================================================
> --- gcc/ginclude/stdatomic.h (revision 204711)
> +++ gcc/ginclude/stdatomic.h (working copy)
> @@ -87,7 +87,7 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
> #define kill_dependency(Y) \
> __extension__ \
> ({ \
> - __typeof__ (Y) __kill_dependency_tmp = (Y); \
> + __auto_type __kill_dependency_tmp = (Y); \
> __kill_dependency_tmp; \
> })
>
> @@ -121,9 +121,9 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
> __atomic_type_lock_free (void * _Atomic)
>
>
> -/* Note that these macros require __typeof__ to remove _Atomic
> - qualifiers (and const qualifiers, if those are valid on macro
> - operands).
> +/* Note that these macros require __typeof__ and __auto_type to remove
> + _Atomic qualifiers (and const qualifiers, if those are valid on
> + macro operands).
>
> Also note that the header file uses the generic form of __atomic
> builtins, which requires the address to be taken of the value
> @@ -132,11 +132,12 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
> these to lock-free _N variants if possible, and throw away the
> temps. */
>
> -#define atomic_store_explicit(PTR, VAL, MO) \
> - __extension__ \
> - ({ \
> - __typeof__ (*(PTR)) __atomic_store_tmp = (VAL); \
> - __atomic_store ((PTR), &__atomic_store_tmp, (MO)); \
> +#define atomic_store_explicit(PTR, VAL, MO) \
> + __extension__ \
> + ({ \
> + __auto_type __atomic_store_ptr = (PTR); \
> + __typeof__ (*__atomic_store_ptr) __atomic_store_tmp = (VAL); \
> + __atomic_store (__atomic_store_ptr, &__atomic_store_tmp, (MO)); \
> })
>
> #define atomic_store(PTR, VAL) \
> @@ -146,8 +147,9 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
> #define atomic_load_explicit(PTR, MO) \
> __extension__ \
> ({ \
> - __typeof__ (*(PTR)) __atomic_load_tmp; \
> - __atomic_load ((PTR), &__atomic_load_tmp, (MO)); \
> + __auto_type __atomic_load_ptr = (PTR); \
> + __typeof__ (*__atomic_load_ptr) __atomic_load_tmp; \
> + __atomic_load (__atomic_load_ptr, &__atomic_load_tmp, (MO)); \
> __atomic_load_tmp; \
> })
>
> @@ -157,8 +159,10 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
> #define atomic_exchange_explicit(PTR, VAL, MO) \
> __extension__ \
> ({ \
> - __typeof__ (*(PTR)) __atomic_exchange_val = (VAL), __atomic_exchange_tmp; \
> - __atomic_exchange ((PTR), &__atomic_exchange_val, \
> + __auto_type __atomic_exchange_ptr = (PTR); \
> + __typeof__ (*__atomic_exchange_ptr) __atomic_exchange_val = (VAL); \
> + __typeof__ (*__atomic_exchange_ptr) __atomic_exchange_tmp; \
> + __atomic_exchange (__atomic_exchange_ptr, &__atomic_exchange_val, \
> &__atomic_exchange_tmp, (MO)); \
> __atomic_exchange_tmp; \
> })
> @@ -170,8 +174,10 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
> #define atomic_compare_exchange_strong_explicit(PTR, VAL, DES, SUC, FAIL) \
> __extension__ \
> ({ \
> - __typeof__ (*(PTR)) __atomic_compare_exchange_tmp = (DES); \
> - __atomic_compare_exchange ((PTR), (VAL), \
> + __auto_type __atomic_compare_exchange_ptr = (PTR); \
> + __typeof__ (*__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \
> + = (DES); \
> + __atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \
> &__atomic_compare_exchange_tmp, 0, \
> (SUC), (FAIL)); \
> })
> @@ -183,8 +189,10 @@ typedef _Atomic __UINTMAX_TYPE__ atomic_uintmax_t;
> #define atomic_compare_exchange_weak_explicit(PTR, VAL, DES, SUC, FAIL) \
> __extension__ \
> ({ \
> - __typeof__ (*(PTR)) __atomic_compare_exchange_tmp = (DES); \
> - __atomic_compare_exchange ((PTR), (VAL), \
> + __auto_type __atomic_compare_exchange_ptr = (PTR); \
> + __typeof__ (*__atomic_compare_exchange_ptr) __atomic_compare_exchange_tmp \
> + = (DES); \
> + __atomic_compare_exchange (__atomic_compare_exchange_ptr, (VAL), \
> &__atomic_compare_exchange_tmp, 1, \
> (SUC), (FAIL)); \
> })
> Index: gcc/testsuite/gcc.dg/auto-type-1.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/auto-type-1.c (revision 0)
> +++ gcc/testsuite/gcc.dg/auto-type-1.c (revision 0)
> @@ -0,0 +1,37 @@
> +/* Test __auto_type. Test correct uses. */
> +/* { dg-do run } */
> +/* { dg-options "" } */
> +
> +extern void abort (void);
> +extern void exit (int);
> +
> +__auto_type i = 1;
> +extern int i;
> +__auto_type c = (char) 1;
> +extern char c;
> +static __auto_type u = 10U;
> +extern unsigned int u;
> +const __auto_type ll = 1LL;
> +extern const long long ll;
> +
> +int
> +main (void)
> +{
> + if (i != 1 || c != 1 || u != 10U)
> + abort ();
> + __auto_type ai = i;
> + int *aip = &ai;
> + if (ai != 1)
> + abort ();
> + __auto_type p = (int (*) [++i]) 0;
> + if (i != 2)
> + abort ();
> + if (sizeof (*p) != 2 * sizeof (int))
> + abort ();
> + int vla[u][u];
> + int (*vp)[u] = &vla[0];
> + __auto_type vpp = ++vp;
> + if (vp != &vla[1])
> + abort ();
> + exit (0);
> +}
> Index: gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c (revision 0)
> +++ gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c (revision 0)
> @@ -0,0 +1,68 @@
> +/* Test atomic operations on expressions of variably modified type
> + with side effects. */
> +/* { dg-do run } */
> +/* { dg-options "-std=c11 -pedantic-errors" } */
> +
> +#include <stdatomic.h>
> +
> +extern void abort (void);
> +
> +int s = 5;
> +
> +int count = 0;
> +
> +int
> +func (void)
> +{
> + count++;
> + return 0;
> +}
> +
> +int
> +main (void)
> +{
> + int vla[s][s];
> + int (*_Atomic p)[s] = &vla[0];
> + int (*b)[s] = kill_dependency (++p);
> + if (b != &vla[1] || p != &vla[1])
> + abort ();
> + int (*_Atomic *q)[s] = &p;
> + atomic_store_explicit (q + func (), &vla[0], memory_order_seq_cst);
> + if (count != 1)
> + abort ();
> + atomic_store (q + func (), &vla[0]);
> + if (count != 2)
> + abort ();
> + (void) atomic_load_explicit (q + func (), memory_order_seq_cst);
> + if (count != 3)
> + abort ();
> + (void) atomic_load (q + func ());
> + if (count != 4)
> + abort ();
> + (void) atomic_exchange_explicit (q + func (), &vla[0], memory_order_seq_cst);
> + if (count != 5)
> + abort ();
> + (void) atomic_exchange (q + func (), &vla[0]);
> + if (count != 6)
> + abort ();
> + int vla2[s][s];
> + int (*p2)[s] = &vla2[0];
> + int (**qna)[s] = &p2;
> + (void) atomic_compare_exchange_strong_explicit (q + func (), qna, &vla[0],
> + memory_order_seq_cst,
> + memory_order_seq_cst);
> + if (count != 7)
> + abort ();
> + (void) atomic_compare_exchange_strong (q + func (), qna, &vla[0]);
> + if (count != 8)
> + abort ();
> + (void) atomic_compare_exchange_weak_explicit (q + func (), qna, &vla[0],
> + memory_order_seq_cst,
> + memory_order_seq_cst);
> + if (count != 9)
> + abort ();
> + (void) atomic_compare_exchange_weak (q + func (), qna, &vla[0]);
> + if (count != 10)
> + abort ();
> + return 0;
> +}
> Index: gcc/testsuite/gcc.dg/auto-type-2.c
> ===================================================================
> --- gcc/testsuite/gcc.dg/auto-type-2.c (revision 0)
> +++ gcc/testsuite/gcc.dg/auto-type-2.c (revision 0)
> @@ -0,0 +1,23 @@
> +/* Test __auto_type. Test invalid uses. */
> +/* { dg-do compile } */
> +/* { dg-options "" } */
> +
> +__auto_type; /* { dg-error "empty declaration" } */
> +__auto_type *p = (int *) 0; /* { dg-error "plain identifier" } */
> +struct s0 { int i : 1; } x;
> +void f (void) { __auto_type v = x.i; } /* { dg-error "bit-field initializer" } */
> +__auto_type i; /* { dg-error "initialized data declaration" } */
> +__auto_type g { } /* { dg-error "initialized data declaration" } */
> +__auto_type a = 1, b = 2; /* { dg-error "single declarator" } */
> +__auto_type long e0 = 0; /* { dg-error "__auto_type" } */
> +__auto_type short e1 = 0; /* { dg-error "__auto_type" } */
> +__auto_type signed e2 = 0; /* { dg-error "__auto_type" } */
> +__auto_type unsigned e3 = 0; /* { dg-error "__auto_type" } */
> +__auto_type _Complex e4 = 0; /* { dg-error "__auto_type" } */
> +long __auto_type e5 = 0; /* { dg-error "__auto_type" } */
> +short __auto_type e6 = 0; /* { dg-error "__auto_type" } */
> +signed __auto_type e7 = 0; /* { dg-error "__auto_type" } */
> +unsigned __auto_type e8 = 0; /* { dg-error "__auto_type" } */
> +_Complex __auto_type e9 = 0; /* { dg-error "__auto_type" } */
> +int __auto_type e10 = 0; /* { dg-error "two or more data types" } */
> +__auto_type _Bool e11 = 0; /* { dg-error "two or more data types" } */
> Index: gcc/doc/extend.texi
> ===================================================================
> --- gcc/doc/extend.texi (revision 204711)
> +++ gcc/doc/extend.texi (working copy)
> @@ -153,7 +153,7 @@ the value of an enumeration constant, the width of
> the initial value of a static variable.
>
> If you don't know the type of the operand, you can still do this, but you
> -must use @code{typeof} (@pxref{Typeof}).
> +must use @code{typeof} or @code{__auto_type} (@pxref{Typeof}).
>
> In G++, the result value of a statement expression undergoes array and
> function pointer decay, and is returned by value to the enclosing
> @@ -755,6 +755,35 @@ Thus, @code{array (pointer (char), 4)} is the type
> pointers to @code{char}.
> @end itemize
>
> +In GNU C, but not GNU C++, you may also declare the type of a variable
> +as @code{__auto_type}. In that case, the declaration must declare
> +only one variable, whose declarator must just be an identifier, the
> +declaration must be initialized, and the type of the variable is
> +determined by the initializer; the name of the variable is not in
> +scope until after the initializer. (In C++, you should use C++11
> +@code{auto} for this purpose.) Using @code{__auto_type}, the
> +``maximum'' macro above could be written as:
> +
> +@smallexample
> +#define max(a,b) \
> + (@{ __auto_type _a = (a); \
> + __auto_type _b = (b); \
> + _a > _b ? _a : _b; @})
> +@end smallexample
> +
> +Using @code{__auto_type} instead of @code{typeof} has two advantages:
> +
> +@itemize @bullet
> +@item Each argument to the macro appears only once in the expansion of
> +the macro. This prevents the size of the macro expansion growing
> +exponentially when calls to such macros are nested inside arguments of
> +such macros.
> +
> +@item If the argument to the macro has variably modified type, it is
> +evaluated only once when using @code{__auto_type}, but twice if
> +@code{typeof} is used.
> +@end itemize
> +
> @emph{Compatibility Note:} In addition to @code{typeof}, GCC 2 supported
> a more limited extension that permitted one to write
>
> Index: gcc/c/c-tree.h
> ===================================================================
> --- gcc/c/c-tree.h (revision 204711)
> +++ gcc/c/c-tree.h (working copy)
> @@ -214,7 +214,8 @@ enum c_typespec_keyword {
> cts_dfloat64,
> cts_dfloat128,
> cts_fract,
> - cts_accum
> + cts_accum,
> + cts_auto_type
> };
>
> /* This enum lists all the possible declarator specifiers, storage
> Index: gcc/c/c-decl.c
> ===================================================================
> --- gcc/c/c-decl.c (revision 204711)
> +++ gcc/c/c-decl.c (working copy)
> @@ -9115,6 +9115,10 @@ declspecs_add_type (location_t loc, struct c_decls
> error_at (loc,
> ("both %<long%> and %<short%> in "
> "declaration specifiers"));
> + else if (specs->typespec_word == cts_auto_type)
> + error_at (loc,
> + ("both %<long%> and %<__auto_type%> in "
> + "declaration specifiers"));
> else if (specs->typespec_word == cts_void)
> error_at (loc,
> ("both %<long%> and %<void%> in "
> @@ -9159,6 +9163,10 @@ declspecs_add_type (location_t loc, struct c_decls
> error_at (loc,
> ("both %<long%> and %<short%> in "
> "declaration specifiers"));
> + else if (specs->typespec_word == cts_auto_type)
> + error_at (loc,
> + ("both %<short%> and %<__auto_type%> in "
> + "declaration specifiers"));
> else if (specs->typespec_word == cts_void)
> error_at (loc,
> ("both %<short%> and %<void%> in "
> @@ -9207,6 +9215,10 @@ declspecs_add_type (location_t loc, struct c_decls
> error_at (loc,
> ("both %<signed%> and %<unsigned%> in "
> "declaration specifiers"));
> + else if (specs->typespec_word == cts_auto_type)
> + error_at (loc,
> + ("both %<signed%> and %<__auto_type%> in "
> + "declaration specifiers"));
> else if (specs->typespec_word == cts_void)
> error_at (loc,
> ("both %<signed%> and %<void%> in "
> @@ -9247,6 +9259,10 @@ declspecs_add_type (location_t loc, struct c_decls
> error_at (loc,
> ("both %<signed%> and %<unsigned%> in "
> "declaration specifiers"));
> + else if (specs->typespec_word == cts_auto_type)
> + error_at (loc,
> + ("both %<unsigned%> and %<__auto_type%> in "
> + "declaration specifiers"));
> else if (specs->typespec_word == cts_void)
> error_at (loc,
> ("both %<unsigned%> and %<void%> in "
> @@ -9286,8 +9302,12 @@ declspecs_add_type (location_t loc, struct c_decls
> if (!flag_isoc99 && !in_system_header_at (loc))
> pedwarn (loc, OPT_Wpedantic,
> "ISO C90 does not support complex types");
> - if (specs->typespec_word == cts_void)
> + if (specs->typespec_word == cts_auto_type)
> error_at (loc,
> + ("both %<complex%> and %<__auto_type%> in "
> + "declaration specifiers"));
> + else if (specs->typespec_word == cts_void)
> + error_at (loc,
> ("both %<complex%> and %<void%> in "
> "declaration specifiers"));
> else if (specs->typespec_word == cts_bool)
> @@ -9334,6 +9354,10 @@ declspecs_add_type (location_t loc, struct c_decls
> ("both %<_Sat%> and %<__int128%> in "
> "declaration specifiers"));
> }
> + else if (specs->typespec_word == cts_auto_type)
> + error_at (loc,
> + ("both %<_Sat%> and %<__auto_type%> in "
> + "declaration specifiers"));
> else if (specs->typespec_word == cts_void)
> error_at (loc,
> ("both %<_Sat%> and %<void%> in "
> @@ -9392,7 +9416,8 @@ declspecs_add_type (location_t loc, struct c_decls
> else
> {
> /* "void", "_Bool", "char", "int", "float", "double", "_Decimal32",
> - "__int128", "_Decimal64", "_Decimal128", "_Fract" or "_Accum". */
> + "__int128", "_Decimal64", "_Decimal128", "_Fract", "_Accum" or
> + "__auto_type". */
> if (specs->typespec_word != cts_none)
> {
> error_at (loc,
> @@ -9401,6 +9426,37 @@ declspecs_add_type (location_t loc, struct c_decls
> }
> switch (i)
> {
> + case RID_AUTO_TYPE:
> + if (specs->long_p)
> + error_at (loc,
> + ("both %<long%> and %<__auto_type%> in "
> + "declaration specifiers"));
> + else if (specs->short_p)
> + error_at (loc,
> + ("both %<short%> and %<__auto_type%> in "
> + "declaration specifiers"));
> + else if (specs->signed_p)
> + error_at (loc,
> + ("both %<signed%> and %<__auto_type%> in "
> + "declaration specifiers"));
> + else if (specs->unsigned_p)
> + error_at (loc,
> + ("both %<unsigned%> and %<__auto_type%> in "
> + "declaration specifiers"));
> + else if (specs->complex_p)
> + error_at (loc,
> + ("both %<complex%> and %<__auto_type%> in "
> + "declaration specifiers"));
> + else if (specs->saturating_p)
> + error_at (loc,
> + ("both %<_Sat%> and %<__auto_type%> in "
> + "declaration specifiers"));
> + else
> + {
> + specs->typespec_word = cts_auto_type;
> + specs->locations[cdw_typespec] = loc;
> + }
> + return specs;
> case RID_INT128:
> if (int128_integer_type_node == NULL_TREE)
> {
> @@ -9956,6 +10012,12 @@ finish_declspecs (struct c_declspecs *specs)
> /* Now compute the actual type. */
> switch (specs->typespec_word)
> {
> + case cts_auto_type:
> + gcc_assert (!specs->long_p && !specs->short_p
> + && !specs->signed_p && !specs->unsigned_p
> + && !specs->complex_p);
> + /* Type to be filled in later. */
> + break;
> case cts_void:
> gcc_assert (!specs->long_p && !specs->short_p
> && !specs->signed_p && !specs->unsigned_p
> Index: gcc/c/c-parser.c
> ===================================================================
> --- gcc/c/c-parser.c (revision 204711)
> +++ gcc/c/c-parser.c (working copy)
> @@ -501,6 +501,7 @@ c_token_starts_typename (c_token *token)
> case RID_FRACT:
> case RID_ACCUM:
> case RID_SAT:
> + case RID_AUTO_TYPE:
> return true;
> default:
> return false;
> @@ -659,6 +660,7 @@ c_token_starts_declspecs (c_token *token)
> case RID_SAT:
> case RID_ALIGNAS:
> case RID_ATOMIC:
> + case RID_AUTO_TYPE:
> return true;
> default:
> return false;
> @@ -1128,7 +1130,7 @@ static void c_parser_declaration_or_fndef (c_parse
> static void c_parser_static_assert_declaration_no_semi (c_parser *);
> static void c_parser_static_assert_declaration (c_parser *);
> static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
> - bool, bool, enum c_lookahead_kind);
> + bool, bool, bool, enum c_lookahead_kind);
> static struct c_typespec c_parser_enum_specifier (c_parser *);
> static struct c_typespec c_parser_struct_or_union_specifier (c_parser *);
> static tree c_parser_struct_declaration (c_parser *);
> @@ -1499,7 +1501,7 @@ c_parser_declaration_or_fndef (c_parser *parser, b
> }
>
> c_parser_declspecs (parser, specs, true, true, start_attr_ok,
> - true, cla_nonabstract_decl);
> + true, true, cla_nonabstract_decl);
> if (parser->error)
> {
> c_parser_skip_to_end_of_block_or_statement (parser);
> @@ -1512,9 +1514,12 @@ c_parser_declaration_or_fndef (c_parser *parser, b
> return;
> }
> finish_declspecs (specs);
> + bool auto_type_p = specs->typespec_word == cts_auto_type;
> if (c_parser_next_token_is (parser, CPP_SEMICOLON))
> {
> - if (empty_ok)
> + if (auto_type_p)
> + error_at (here, "%<__auto_type%> in empty declaration");
> + else if (empty_ok)
> shadow_tag (specs);
> else
> {
> @@ -1537,7 +1542,7 @@ c_parser_declaration_or_fndef (c_parser *parser, b
> shadow_tag_warned (specs, 1);
> return;
> }
> - else if (c_dialect_objc ())
> + else if (c_dialect_objc () && !auto_type_p)
> {
> /* Prefix attributes are an error on method decls. */
> switch (c_parser_peek_token (parser)->type)
> @@ -1640,6 +1645,14 @@ c_parser_declaration_or_fndef (c_parser *parser, b
> c_parser_skip_to_end_of_block_or_statement (parser);
> return;
> }
> + if (auto_type_p && declarator->kind != cdk_id)
> + {
> + error_at (here,
> + "%<__auto_type%> requires a plain identifier"
> + " as declarator");
> + c_parser_skip_to_end_of_block_or_statement (parser);
> + return;
> + }
> if (c_parser_next_token_is (parser, CPP_EQ)
> || c_parser_next_token_is (parser, CPP_COMMA)
> || c_parser_next_token_is (parser, CPP_SEMICOLON)
> @@ -1667,19 +1680,72 @@ c_parser_declaration_or_fndef (c_parser *parser, b
> struct c_expr init;
> location_t init_loc;
> c_parser_consume_token (parser);
> - /* The declaration of the variable is in effect while
> - its initializer is parsed. */
> - d = start_decl (declarator, specs, true,
> - chainon (postfix_attrs, all_prefix_attrs));
> - if (!d)
> - d = error_mark_node;
> - if (omp_declare_simd_clauses.exists ())
> - c_finish_omp_declare_simd (parser, d, NULL_TREE,
> - omp_declare_simd_clauses);
> - start_init (d, asm_name, global_bindings_p ());
> - init_loc = c_parser_peek_token (parser)->location;
> - init = c_parser_initializer (parser);
> - finish_init ();
> + if (auto_type_p)
> + {
> + start_init (NULL_TREE, asm_name, global_bindings_p ());
> + init_loc = c_parser_peek_token (parser)->location;
> + init = c_parser_expr_no_commas (parser, NULL);
> + if (TREE_CODE (init.value) == COMPONENT_REF
> + && DECL_C_BIT_FIELD (TREE_OPERAND (init.value, 1)))
> + error_at (here,
> + "%<__auto_type%> used with a bit-field"
> + " initializer");
> + init = convert_lvalue_to_rvalue (init_loc, init, true, true);
> + tree init_type = TREE_TYPE (init.value);
> + /* As with typeof, remove _Atomic and const
> + qualifiers from atomic types. */
> + if (init_type != error_mark_node && TYPE_ATOMIC (init_type))
> + init_type
> + = c_build_qualified_type (init_type,
> + (TYPE_QUALS (init_type)
> + & ~(TYPE_QUAL_ATOMIC
> + | TYPE_QUAL_CONST)));
> + bool vm_type = variably_modified_type_p (init_type,
> + NULL_TREE);
> + if (vm_type)
> + init.value = c_save_expr (init.value);
> + finish_init ();
> + specs->typespec_kind = ctsk_typeof;
> + specs->locations[cdw_typedef] = init_loc;
> + specs->typedef_p = true;
> + specs->type = init_type;
> + if (vm_type)
> + {
> + bool maybe_const = true;
> + tree type_expr = c_fully_fold (init.value, false,
> + &maybe_const);
> + specs->expr_const_operands &= maybe_const;
> + if (specs->expr)
> + specs->expr = build2 (COMPOUND_EXPR,
> + TREE_TYPE (type_expr),
> + specs->expr, type_expr);
> + else
> + specs->expr = type_expr;
> + }
> + d = start_decl (declarator, specs, true,
> + chainon (postfix_attrs, all_prefix_attrs));
> + if (!d)
> + d = error_mark_node;
> + if (omp_declare_simd_clauses.exists ())
> + c_finish_omp_declare_simd (parser, d, NULL_TREE,
> + omp_declare_simd_clauses);
> + }
> + else
> + {
> + /* The declaration of the variable is in effect while
> + its initializer is parsed. */
> + d = start_decl (declarator, specs, true,
> + chainon (postfix_attrs, all_prefix_attrs));
> + if (!d)
> + d = error_mark_node;
> + if (omp_declare_simd_clauses.exists ())
> + c_finish_omp_declare_simd (parser, d, NULL_TREE,
> + omp_declare_simd_clauses);
> + start_init (d, asm_name, global_bindings_p ());
> + init_loc = c_parser_peek_token (parser)->location;
> + init = c_parser_initializer (parser);
> + finish_init ();
> + }
> if (d != error_mark_node)
> {
> maybe_warn_string_init (TREE_TYPE (d), init);
> @@ -1689,6 +1755,14 @@ c_parser_declaration_or_fndef (c_parser *parser, b
> }
> else
> {
> + if (auto_type_p)
> + {
> + error_at (here,
> + "%<__auto_type%> requires an initialized "
> + "data declaration");
> + c_parser_skip_to_end_of_block_or_statement (parser);
> + return;
> + }
> tree d = start_decl (declarator, specs, false,
> chainon (postfix_attrs,
> all_prefix_attrs));
> @@ -1728,6 +1802,14 @@ c_parser_declaration_or_fndef (c_parser *parser, b
> }
> if (c_parser_next_token_is (parser, CPP_COMMA))
> {
> + if (auto_type_p)
> + {
> + error_at (here,
> + "%<__auto_type%> may only be used with"
> + " a single declarator");
> + c_parser_skip_to_end_of_block_or_statement (parser);
> + return;
> + }
> c_parser_consume_token (parser);
> if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
> all_prefix_attrs = chainon (c_parser_attributes (parser),
> @@ -1757,6 +1839,13 @@ c_parser_declaration_or_fndef (c_parser *parser, b
> return;
> }
> }
> + else if (auto_type_p)
> + {
> + error_at (here,
> + "%<__auto_type%> requires an initialized data declaration");
> + c_parser_skip_to_end_of_block_or_statement (parser);
> + return;
> + }
> else if (!fndef_ok)
> {
> c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, "
> @@ -1949,7 +2038,7 @@ c_parser_static_assert_declaration_no_semi (c_pars
> Storage class specifiers are accepted iff SCSPEC_OK; type
> specifiers are accepted iff TYPESPEC_OK; alignment specifiers are
> accepted iff ALIGNSPEC_OK; attributes are accepted at the start
> - iff START_ATTR_OK.
> + iff START_ATTR_OK; __auto_type is accepted iff AUTO_TYPE_OK.
>
> declaration-specifiers:
> storage-class-specifier declaration-specifiers[opt]
> @@ -2030,6 +2119,7 @@ c_parser_static_assert_declaration_no_semi (c_pars
>
> type-specifier:
> typeof-specifier
> + __auto_type
> __int128
> _Decimal32
> _Decimal64
> @@ -2055,7 +2145,8 @@ c_parser_static_assert_declaration_no_semi (c_pars
> static void
> c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
> bool scspec_ok, bool typespec_ok, bool start_attr_ok,
> - bool alignspec_ok, enum c_lookahead_kind la)
> + bool alignspec_ok, bool auto_type_ok,
> + enum c_lookahead_kind la)
> {
> bool attrs_ok = start_attr_ok;
> bool seen_type = specs->typespec_kind != ctsk_none;
> @@ -2177,6 +2268,10 @@ c_parser_declspecs (c_parser *parser, struct c_dec
> c_parser_peek_token (parser)->value);
> c_parser_consume_token (parser);
> break;
> + case RID_AUTO_TYPE:
> + if (!auto_type_ok)
> + goto out;
> + /* Fall through. */
> case RID_UNSIGNED:
> case RID_LONG:
> case RID_INT128:
> @@ -2722,7 +2817,7 @@ c_parser_struct_declaration (c_parser *parser)
> of N1731.
> <http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1731.pdf> */
> c_parser_declspecs (parser, specs, false, true, true,
> - true, cla_nonabstract_decl);
> + true, false, cla_nonabstract_decl);
> if (parser->error)
> return NULL_TREE;
> if (!specs->declspecs_seen_p)
> @@ -3045,7 +3140,7 @@ c_parser_declarator (c_parser *parser, bool type_s
> struct c_declarator *inner;
> c_parser_consume_token (parser);
> c_parser_declspecs (parser, quals_attrs, false, false, true,
> - false, cla_prefer_id);
> + false, false, cla_prefer_id);
> inner = c_parser_declarator (parser, type_seen_p, kind, seen_id);
> if (inner == NULL)
> return NULL;
> @@ -3201,13 +3296,13 @@ c_parser_direct_declarator_inner (c_parser *parser
> dimen.original_type = NULL_TREE;
> c_parser_consume_token (parser);
> c_parser_declspecs (parser, quals_attrs, false, false, true,
> - false, cla_prefer_id);
> + false, false, cla_prefer_id);
> static_seen = c_parser_next_token_is_keyword (parser, RID_STATIC);
> if (static_seen)
> c_parser_consume_token (parser);
> if (static_seen && !quals_attrs->declspecs_seen_p)
> c_parser_declspecs (parser, quals_attrs, false, false, true,
> - false, cla_prefer_id);
> + false, false, cla_prefer_id);
> if (!quals_attrs->declspecs_seen_p)
> quals_attrs = NULL;
> /* If "static" is present, there must be an array dimension.
> @@ -3510,7 +3605,7 @@ c_parser_parameter_declaration (c_parser *parser,
> declspecs_add_attrs (input_location, specs, attrs);
> attrs = NULL_TREE;
> }
> - c_parser_declspecs (parser, specs, true, true, true, true,
> + c_parser_declspecs (parser, specs, true, true, true, true, false,
> cla_nonabstract_decl);
> finish_declspecs (specs);
> pending_xref_error ();
> @@ -3643,6 +3738,7 @@ c_parser_attribute_any_word (c_parser *parser)
> case RID_TRANSACTION_ATOMIC:
> case RID_TRANSACTION_CANCEL:
> case RID_ATOMIC:
> + case RID_AUTO_TYPE:
> ok = true;
> break;
> default:
> @@ -3821,7 +3917,7 @@ c_parser_type_name (c_parser *parser)
> struct c_declarator *declarator;
> struct c_type_name *ret;
> bool dummy = false;
> - c_parser_declspecs (parser, specs, false, true, true, false,
> + c_parser_declspecs (parser, specs, false, true, true, false, false,
> cla_prefer_type);
> if (!specs->declspecs_seen_p)
> {
> @@ -8702,6 +8798,7 @@ c_parser_objc_selector (c_parser *parser)
> case RID_VOID:
> case RID_BOOL:
> case RID_ATOMIC:
> + case RID_AUTO_TYPE:
> c_parser_consume_token (parser);
> return value;
> default:
> Index: gcc/c-family/c-common.c
> ===================================================================
> --- gcc/c-family/c-common.c (revision 204711)
> +++ gcc/c-family/c-common.c (working copy)
> @@ -433,6 +433,7 @@ const struct c_common_resword c_common_reswords[]
> { "__asm__", RID_ASM, 0 },
> { "__attribute", RID_ATTRIBUTE, 0 },
> { "__attribute__", RID_ATTRIBUTE, 0 },
> + { "__auto_type", RID_AUTO_TYPE, D_CONLY },
> { "__bases", RID_BASES, D_CXXONLY },
> { "__builtin_choose_expr", RID_CHOOSE_EXPR, D_CONLY },
> { "__builtin_complex", RID_BUILTIN_COMPLEX, D_CONLY },
> @@ -11550,6 +11551,7 @@ keyword_begins_type_specifier (enum rid keyword)
> {
> switch (keyword)
> {
> + case RID_AUTO_TYPE:
> case RID_INT:
> case RID_CHAR:
> case RID_FLOAT:
> Index: gcc/c-family/c-common.h
> ===================================================================
> --- gcc/c-family/c-common.h (revision 204711)
> +++ gcc/c-family/c-common.h (working copy)
> @@ -102,7 +102,7 @@ enum rid
> RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
> RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
> RID_DFLOAT32, RID_DFLOAT64, RID_DFLOAT128,
> - RID_FRACT, RID_ACCUM,
> + RID_FRACT, RID_ACCUM, RID_AUTO_TYPE,
>
> /* C11 */
> RID_ALIGNAS, RID_GENERIC,
>
> --
> Joseph S. Myers
> joseph@codesourcery.com