On Wed, Nov 13, 2013 at 1:39 AM, Joseph S. Myers <jos...@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 <jos...@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 <jos...@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 <jos...@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 <jos...@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 > jos...@codesourcery.com