c-common.h (enum rid): New constant.

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
This commit is contained in:
Tom Tromey 2013-07-23 01:54:24 +00:00 committed by Joseph Myers
parent ee07556fbd
commit 433cc7b037
8 changed files with 328 additions and 1 deletions

View 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řej Bílka <neleai@seznam.cz>
* c-common.c: Fix typos.

View 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 },

View 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. */

View 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

View 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;

View 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

View File

@ -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);
}

View File

@ -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" } */
}