]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
extend.texi (Statement Exprs, Typeof): Discuss __auto_type.
authorJoseph Myers <joseph@codesourcery.com>
Wed, 13 Nov 2013 00:38:49 +0000 (00:38 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Wed, 13 Nov 2013 00:38:49 +0000 (00:38 +0000)
* 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:
* 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:
* 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:
* gcc.dg/atomic/stdatomic-vm.c, gcc.dg/auto-type-1.c,
gcc.dg/auto-type-2.c: New tests.

From-SVN: r204731

14 files changed:
gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c/ChangeLog
gcc/c/c-decl.c
gcc/c/c-parser.c
gcc/c/c-tree.h
gcc/doc/extend.texi
gcc/ginclude/stdatomic.h
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/auto-type-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/auto-type-2.c [new file with mode: 0644]

index 2c0554b811192346ee5054e66fe5c312195e9d1c..95e51ed554cd8abf1876f92cd0421384154bfde1 100644 (file)
@@ -1,3 +1,12 @@
+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.
+
 2013-11-12  Jeff Law  <law@redhat.com>
 
        * tree-ssa-threadedge.c (thread_around_empty_blocks): New
index 57063bc5f76123ae751ff4cc3e70a44e031357a3..e4e6163e0916cebf64cb9aacf433a99cc3fc8760 100644 (file)
@@ -1,3 +1,9 @@
+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.
+
 2013-11-12  Andrew MacLeod  <amacleod@redhat.com>
 
        * c-family/c-common.c: Include gimplify.h.
index 835d22c6cf90028b7dad2669c96254bdfe13d801..1f5e4ededa170c026c7632b77a4a9ad5480ac7ff 100644 (file)
@@ -434,6 +434,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 },
@@ -11551,6 +11552,7 @@ keyword_begins_type_specifier (enum rid keyword)
 {
   switch (keyword)
     {
+    case RID_AUTO_TYPE:
     case RID_INT:
     case RID_CHAR:
     case RID_FLOAT:
index 74fd59fb5eedd10fa44ac761a3d15e8650d26333..d9d2c44097aa1f004e43639f6c88924093bcd116 100644 (file)
@@ -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,
index e95c54dd2bee9331b48b6fcbe76f1236fd39066d..b9b9dc9cacc61e0f78686ce5119f68f118bf852b 100644 (file)
@@ -1,3 +1,19 @@
+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.
+
 2013-11-12  Andrew MacLeod  <amacleod@redhat.com>
 
        * c/c-typeck.c: Include gimplify.h.
index 6fe418e9e4cf225853ac64b6c5ca91808c369028..92fc68f2017e5035d45e5dc6a7facbf6d47843c0 100644 (file)
@@ -9115,6 +9115,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                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_declspecs *specs,
                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_declspecs *specs,
                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_declspecs *specs,
                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,7 +9302,11 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
              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"));
@@ -9334,6 +9354,10 @@ declspecs_add_type (location_t loc, struct c_declspecs *specs,
                            ("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_declspecs *specs,
       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_declspecs *specs,
            }
          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 5b4665a2a8dd99672c6765e61d60747517a0490e..ffbf3c41f93d4d2125bdebbfc4ea8f0a2169b512 100644 (file)
@@ -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_parser *, bool, bool, bool,
 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, bool fndef_ok,
     }
 
   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, bool fndef_ok,
       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, bool fndef_ok,
       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, bool fndef_ok,
          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, bool fndef_ok,
              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, bool fndef_ok,
            }
          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, bool fndef_ok,
            }
          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, bool fndef_ok,
              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_parser *parser)
    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_parser *parser)
 
    type-specifier:
      typeof-specifier
+     __auto_type
      __int128
      _Decimal32
      _Decimal64
@@ -2055,7 +2145,8 @@ c_parser_static_assert_declaration_no_semi (c_parser *parser)
 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_declspecs *specs,
                                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_seen_p, c_dtr_syn kind,
       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, bool id_present,
       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, tree attrs)
       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 502fdca4d7ed644b2e18aadb801522eb38847714..c4dfc3baf3651d8eba495bdd2531f3d688200a70 100644 (file)
@@ -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 2132b1e5602dff3bbfa6c1bec30a2aa3079a0808..599dee3c3bf204eb3e6e1deaa19e559e56ca925d 100644 (file)
@@ -153,7 +153,7 @@ the value of an enumeration constant, the width of a bit-field, or
 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 of arrays of 4
 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 622577f0877327278e35f6755a1c367365a036d0..b558bf10f1964529879eee5184b760e2425467f6 100644 (file)
@@ -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 09c7f2017af77ba6ac87986b84063db67e18fa9e..2d724f73207f62828cdc3dc25e0794eb6b84b0d4 100644 (file)
@@ -1,3 +1,8 @@
+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.
+
 2013-11-12  Balaji V. Iyer  <balaji.v.iyer@intel.com>
 
        * gcc.dg/cilk-plus/cilk-plus.exp: Added a check for LTO before running
diff --git a/gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c b/gcc/testsuite/gcc.dg/atomic/stdatomic-vm.c
new file mode 100644 (file)
index 0000000..f43fa49
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-type-1.c b/gcc/testsuite/gcc.dg/auto-type-1.c
new file mode 100644 (file)
index 0000000..f47693a
--- /dev/null
@@ -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);
+}
diff --git a/gcc/testsuite/gcc.dg/auto-type-2.c b/gcc/testsuite/gcc.dg/auto-type-2.c
new file mode 100644 (file)
index 0000000..761671b
--- /dev/null
@@ -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" } */