summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2013-07-23 01:54:24 +0000
committerjsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4>2013-07-23 01:54:24 +0000
commit7aa04c8dccb843c102612936b7fbb888e9fdf13f (patch)
tree8f1ed7da1d779f1cb23b3f07c33506309da58d45
parent49a1ed17c25f36fc07d365b2b2f03fef75071a3b (diff)
downloadgcc-7aa04c8dccb843c102612936b7fbb888e9fdf13f.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@201153 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/c-family/ChangeLog5
-rw-r--r--gcc/c-family/c-common.c1
-rw-r--r--gcc/c-family/c-common.h2
-rw-r--r--gcc/c/ChangeLog8
-rw-r--r--gcc/c/c-parser.c223
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.dg/c11-generic-1.c57
-rw-r--r--gcc/testsuite/gcc.dg/c11-generic-2.c27
8 files changed, 328 insertions, 1 deletions
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 66952066dae..487f880e432 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -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řej Bílka <neleai@seznam.cz>
* c-common.c: Fix typos.
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 04d1bd50fa0..7bba376f369 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -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 },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 915887cf327..dc430c3859c 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -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. */
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 15bc1aa26fc..c7ecff8bdae 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -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
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index c7846cedccb..fea153a3808 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 97f52c9f1ac..4cd3d0f62b2 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 00000000000..60ef1f0eb69
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-generic-1.c
@@ -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
index 00000000000..90be650af28
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c11-generic-2.c
@@ -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" } */
+}