This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Add __auto_type C extension, use it in <stdatomic.h>


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]