]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c-common.h (enum rid): New constant.
authorTom Tromey <tromey@redhat.com>
Tue, 23 Jul 2013 01:54:24 +0000 (01:54 +0000)
committerJoseph Myers <jsm28@gcc.gnu.org>
Tue, 23 Jul 2013 01:54:24 +0000 (02:54 +0100)
2013-07-23  Tom Tromey  <tromey@redhat.com>
    Joseph Myers  <joseph@codesourcery.com>

c-family:
* c-common.h (enum rid) <RID_GENERIC>: New constant.
* c-common.c (c_common_reswords): Add _Generic.

c:
* c-parser.c (struct c_generic_association): New.
(c_generic_association_d): New typedef.
(c_parser_generic_selection): New function.
(c_parser_postfix_expression): Handle RID_GENERIC.

testsuite:
* gcc.dg/c11-generic-1.c: New file.
* gcc.dg/c11-generic-2.c: New file.

Co-Authored-By: Joseph Myers <joseph@codesourcery.com>
From-SVN: r201153

gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c/ChangeLog
gcc/c/c-parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/c11-generic-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c11-generic-2.c [new file with mode: 0644]

index 66952066dae9227497f0b0fe2ef05256874b768a..487f880e432b4ea6dc8feef059109fb5c766c3be 100644 (file)
@@ -1,3 +1,8 @@
+2013-07-23  Tom Tromey  <tromey@redhat.com>
+
+       * c-common.h (enum rid) <RID_GENERIC>: New constant.
+       * c-common.c (c_common_reswords): Add _Generic.
+
 2013-07-21   OndÅ\99ej Bílka  <neleai@seznam.cz>
 
        * c-common.c: Fix typos.
index 04d1bd50fa0cedd0a9cb1361cfd80a77b3643891..7bba376f36901b047d4641985aa3c3d91489d425 100644 (file)
@@ -412,6 +412,7 @@ const struct c_common_resword c_common_reswords[] =
   { "_Sat",             RID_SAT,       D_CONLY | D_EXT },
   { "_Static_assert",   RID_STATIC_ASSERT, D_CONLY },
   { "_Noreturn",        RID_NORETURN,  D_CONLY },
+  { "_Generic",         RID_GENERIC,   D_CONLY },
   { "__FUNCTION__",    RID_FUNCTION_NAME, 0 },
   { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
   { "__alignof",       RID_ALIGNOF,    0 },
index 915887cf327c7e22a04e5e2cacd9248dae9fd661..dc430c3859c895b18a13ba0d1a9eefeed354f643 100644 (file)
@@ -105,7 +105,7 @@ enum rid
   RID_FRACT, RID_ACCUM,
 
   /* C11 */
-  RID_ALIGNAS,
+  RID_ALIGNAS, RID_GENERIC,
 
   /* This means to warn that this is a C++ keyword, and then treat it
      as a normal identifier.  */
index 15bc1aa26fc63dfd120e13b73d9905dcfe4b71d7..c7ecff8bdae9eca74501af8d1fd5032fbbdeef45 100644 (file)
@@ -1,3 +1,11 @@
+2013-07-23  Tom Tromey  <tromey@redhat.com>
+           Joseph Myers  <joseph@codesourcery.com>
+
+       * c-parser.c (struct c_generic_association): New.
+       (c_generic_association_d): New typedef.
+       (c_parser_generic_selection): New function.
+       (c_parser_postfix_expression): Handle RID_GENERIC.
+
 2013-07-13  Jason Merrill  <jason@redhat.com>
 
        PR c++/57793
index c7846cedccb24b6c4b8dec5046a488a95206f787..fea153a380856925b7c4f0753a6a4f753843f3f6 100644 (file)
@@ -6232,6 +6232,225 @@ c_parser_get_builtin_args (c_parser *parser, const char *bname,
   return true;
 }
 
+/* This represents a single generic-association.  */
+
+struct c_generic_association
+{
+  /* The location of the starting token of the type.  */
+  location_t type_location;
+  /* The association's type, or NULL_TREE for 'default'..  */
+  tree type;
+  /* The association's expression.  */
+  struct c_expr expression;
+};
+
+/* Parse a generic-selection.  (C11 6.5.1.1).
+   
+   generic-selection:
+     _Generic ( assignment-expression , generic-assoc-list )
+     
+   generic-assoc-list:
+     generic-association
+     generic-assoc-list , generic-association
+   
+   generic-association:
+     type-name : assignment-expression
+     default : assignment-expression
+*/
+
+static struct c_expr
+c_parser_generic_selection (c_parser *parser)
+{
+  vec<c_generic_association> associations = vNULL;
+  struct c_expr selector, error_expr;
+  tree selector_type;
+  struct c_generic_association matched_assoc;
+  bool match_found = false;
+  location_t generic_loc, selector_loc;
+
+  error_expr.original_code = ERROR_MARK;
+  error_expr.original_type = NULL;
+  error_expr.value = error_mark_node;
+  matched_assoc.type_location = UNKNOWN_LOCATION;
+  matched_assoc.type = NULL_TREE;
+  matched_assoc.expression = error_expr;
+
+  gcc_assert (c_parser_next_token_is_keyword (parser, RID_GENERIC));
+  generic_loc = c_parser_peek_token (parser)->location;
+  c_parser_consume_token (parser);
+  if (!flag_isoc11)
+    {
+      if (flag_isoc99)
+       pedwarn (generic_loc, OPT_Wpedantic,
+                "ISO C99 does not support %<_Generic%>");
+      else
+       pedwarn (generic_loc, OPT_Wpedantic,
+                "ISO C90 does not support %<_Generic%>");
+    }
+
+  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+    return error_expr;
+
+  c_inhibit_evaluation_warnings++;
+  selector_loc = c_parser_peek_token (parser)->location;
+  selector = c_parser_expr_no_commas (parser, NULL);
+  selector = default_function_array_conversion (selector_loc, selector);
+  c_inhibit_evaluation_warnings--;
+
+  if (selector.value == error_mark_node)
+    {
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return selector;
+    }
+  selector_type = TREE_TYPE (selector.value);
+  /* In ISO C terms, rvalues (including the controlling expression of
+     _Generic) do not have qualified types.  */
+  if (TREE_CODE (selector_type) != ARRAY_TYPE)
+    selector_type = TYPE_MAIN_VARIANT (selector_type);
+  /* In ISO C terms, _Noreturn is not part of the type of expressions
+     such as &abort, but in GCC it is represented internally as a type
+     qualifier.  */
+  if (FUNCTION_POINTER_TYPE_P (selector_type)
+      && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED)
+    selector_type
+      = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type)));
+
+  if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+    {
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return error_expr;
+    }
+
+  while (1)
+    {
+      struct c_generic_association assoc, *iter;
+      unsigned int ix;
+      c_token *token = c_parser_peek_token (parser);
+
+      assoc.type_location = token->location;
+      if (token->type == CPP_KEYWORD && token->keyword == RID_DEFAULT)
+       {
+         c_parser_consume_token (parser);
+         assoc.type = NULL_TREE;
+       }
+      else
+       {
+         struct c_type_name *type_name;
+
+         type_name = c_parser_type_name (parser);
+         if (type_name == NULL)
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             goto error_exit;
+           }
+         assoc.type = groktypename (type_name, NULL, NULL);
+         if (assoc.type == error_mark_node)
+           {
+             c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+             goto error_exit;
+           }
+
+         if (TREE_CODE (assoc.type) == FUNCTION_TYPE)
+           error_at (assoc.type_location,
+                     "%<_Generic%> association has function type");
+         else if (!COMPLETE_TYPE_P (assoc.type))
+           error_at (assoc.type_location,
+                     "%<_Generic%> association has incomplete type");
+
+         if (variably_modified_type_p (assoc.type, NULL_TREE))
+           error_at (assoc.type_location,
+                     "%<_Generic%> association has "
+                     "variable length type");
+       }
+
+      if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         goto error_exit;
+       }
+
+      assoc.expression = c_parser_expr_no_commas (parser, NULL);
+      if (assoc.expression.value == error_mark_node)
+       {
+         c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+         goto error_exit;
+       }
+
+      for (ix = 0; associations.iterate (ix, &iter); ++ix)
+       {
+         if (assoc.type == NULL_TREE)
+           {
+             if (iter->type == NULL_TREE)
+               {
+                 error_at (assoc.type_location,
+                           "duplicate %<default%> case in %<_Generic%>");
+                 inform (iter->type_location, "original %<default%> is here");
+               }
+           }
+         else if (iter->type != NULL_TREE)
+           {
+             if (comptypes (assoc.type, iter->type))
+               {
+                 error_at (assoc.type_location,
+                           "%<_Generic%> specifies two compatible types");
+                 inform (iter->type_location, "compatible type is here");
+               }
+           }
+       }
+
+      if (assoc.type == NULL_TREE)
+       {
+         if (!match_found)
+           {
+             matched_assoc = assoc;
+             match_found = true;
+           }
+       }
+      else if (comptypes (assoc.type, selector_type))
+       {
+         if (!match_found || matched_assoc.type == NULL_TREE)
+           {
+             matched_assoc = assoc;
+             match_found = true;
+           }
+         else
+           {
+             error_at (assoc.type_location,
+                       "%<_Generic> selector matches multiple associations");
+             inform (matched_assoc.type_location,
+                     "other match is here");
+           }
+       }
+
+      associations.safe_push (assoc);
+
+      if (c_parser_peek_token (parser)->type != CPP_COMMA)
+       break;
+      c_parser_consume_token (parser);
+    }
+
+  associations.release ();
+
+  if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+    {
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+      return error_expr;
+    }
+
+  if (!match_found)
+    {
+      error_at (selector_loc, "%<_Generic%> selector of type %qT is not "
+               "compatible with any association",
+               selector_type);
+      return error_expr;
+    }
+
+  return matched_assoc.expression;
+
+ error_exit:
+  associations.release ();
+  return error_expr;
+}
 
 /* Parse a postfix expression (C90 6.3.1-6.3.2, C99 6.5.1-6.5.2).
 
@@ -6255,6 +6474,7 @@ c_parser_get_builtin_args (c_parser *parser, const char *bname,
      constant
      string-literal
      ( expression )
+     generic-selection
 
    GNU extensions:
 
@@ -6823,6 +7043,9 @@ c_parser_postfix_expression (c_parser *parser)
            expr.value = objc_build_encode_expr (type);
          }
          break;
+       case RID_GENERIC:
+         expr = c_parser_generic_selection (parser);
+         break;
        default:
          c_parser_error (parser, "expected expression");
          expr.value = error_mark_node;
index 97f52c9f1ac6a86cf0a5fe4339a842dee404d1bc..4cd3d0f62b259ab9f3d0fdba8056334adadddff5 100644 (file)
@@ -1,3 +1,9 @@
+2013-07-23  Tom Tromey  <tromey@redhat.com>
+           Joseph Myers  <joseph@codesourcery.com>
+
+       * gcc.dg/c11-generic-1.c: New file.
+       * gcc.dg/c11-generic-2.c: New file.
+
 2013-07-22  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/57906
diff --git a/gcc/testsuite/gcc.dg/c11-generic-1.c b/gcc/testsuite/gcc.dg/c11-generic-1.c
new file mode 100644 (file)
index 0000000..60ef1f0
--- /dev/null
@@ -0,0 +1,57 @@
+/* Test C11 _Generic.  Valid uses.  */
+/* { dg-do run } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+_Noreturn extern void exit (int);
+_Noreturn extern void abort (void);
+
+void
+check (int n)
+{
+  if (n)
+    abort ();
+}
+
+int
+main (void)
+{
+  int n = 0;
+
+  check (_Generic (n++, int: 0));
+  /* _Generic should not evaluate its argument.  */
+  check (n);
+
+  check (_Generic (n, double: n++, default: 0));
+  check (n);
+
+  /* Qualifiers are removed for the purpose of type matching.  */
+  const int cn = 0;
+  check (_Generic (cn, int: 0, default: n++));
+  check (n);
+  check (_Generic ((const int) n, int: 0, default: n++));
+  check (n);
+
+  /* Arrays decay to pointers.  */
+  int a[1];
+  const int ca[1];
+  check (_Generic (a, int *: 0, const int *: n++));
+  check (n);
+  check (_Generic (ca, const int *: 0, int *: n++));
+  check (n);
+
+  /* Functions decay to pointers.  */
+  extern void f (void);
+  check (_Generic (f, void (*) (void): 0, default: n++));
+  check (n);
+
+  /* _Noreturn is not part of the function type.  */
+  check (_Generic (&abort, void (*) (void): 0, default: n++));
+  check (n);
+
+  /* Integer promotions do not occur.  */
+  short s;
+  check (_Generic (s, short: 0, int: n++));
+  check (n);
+
+  exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/c11-generic-2.c b/gcc/testsuite/gcc.dg/c11-generic-2.c
new file mode 100644 (file)
index 0000000..90be650
--- /dev/null
@@ -0,0 +1,27 @@
+/* Test C11 _Generic.  Error cases.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+struct incomplete;
+
+void
+f (int n)
+{
+  /* Multiple 'default's.  */
+  _Generic (n, default: 1, default: 2); /* { dg-error "duplicate .*default.* case" } */
+
+  /* Variably-modified type not ok.  */
+  _Generic (n, int[n]: 0, default: 1); /* { dg-error "variable length type" } */
+  /* Type must be complete.  */
+  _Generic (n, struct incomplete: 0, default: 1); /* { dg-error "incomplete type" } */
+  _Generic (n, void: 0, default: 1); /* { dg-error "incomplete type" } */
+
+  /* Type must be object type.  */
+  _Generic (n, void (void): 0, default: 1); /* { dg-error "function type" } */
+
+  /* Two compatible types in association list.  */
+  _Generic (&n, int: 5, signed int: 7, default: 23); /* { dg-error "two compatible types" } */
+
+  /* No matching association.  */
+  _Generic (n, void *: 5);     /* { dg-error "not compatible with any association" } */
+}