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:
parent
ee07556fbd
commit
433cc7b037
@ -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.
|
||||
|
@ -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 },
|
||||
|
@ -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. */
|
||||
|
@ -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
|
||||
|
223
gcc/c/c-parser.c
223
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;
|
||||
|
@ -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
|
||||
|
57
gcc/testsuite/gcc.dg/c11-generic-1.c
Normal file
57
gcc/testsuite/gcc.dg/c11-generic-1.c
Normal 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);
|
||||
}
|
27
gcc/testsuite/gcc.dg/c11-generic-2.c
Normal file
27
gcc/testsuite/gcc.dg/c11-generic-2.c
Normal 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" } */
|
||||
}
|
Loading…
Reference in New Issue
Block a user