Clang now has an extension which accepts a typename for _Generic. This is simple to implement and is useful.
Do we want this? Clang calls it a "Clang extension" in the pedantic warning. I changed it to "an extension" I am not sure what the policy is. Do we need an extra warning option? Clang has one. No documentation so far. Bootstrapped and regression tested on x86_64-pc-linux-gnu. Martin c: Support typename as selector in _Generic Support typenames as first argument to _Generic which is an extension supported by Clang. It makes it easier to test for types with qualifiers in combination with typeof. gcc/c/: * c-parser.cc (c_parser_generic_selection): Support typename in _Generic selector. gcc/testsuite/: * gnu2x-generic.c: New test. diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 57a01dc2fa3..9aea2425294 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -9312,30 +9312,51 @@ c_parser_generic_selection (c_parser *parser) if (!parens.require_open (parser)) 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) + if (c_token_starts_typename (c_parser_peek_token (parser))) { - c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); - return selector; - } - mark_exp_read (selector.value); - 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))); + /* Language extension introduced by Clang. */ + pedwarn (selector_loc, OPT_Wpedantic, "passing a type argument as " + "first argument to %<_Generic%> is an extension"); + struct c_type_name *type_name; + c_inhibit_evaluation_warnings++; + type_name = c_parser_type_name (parser); + c_inhibit_evaluation_warnings--; + if (NULL == type_name) + { + c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL); + return error_expr; + } + /* Qualifiers are preserved. */ + selector_type = groktypename (type_name, NULL, NULL); + } + else + { + c_inhibit_evaluation_warnings++; + 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; + } + mark_exp_read (selector.value); + 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 %<,%>")) { @@ -9401,7 +9422,7 @@ c_parser_generic_selection (c_parser *parser) assoc.expression = c_parser_expr_no_commas (parser, NULL); if (!match) - c_inhibit_evaluation_warnings--; + c_inhibit_evaluation_warnings--; if (assoc.expression.value == error_mark_node) { diff --git a/gcc/testsuite/gcc.dg/gnu2x-generic.c b/gcc/testsuite/gcc.dg/gnu2x-generic.c new file mode 100644 index 00000000000..82b09578072 --- /dev/null +++ b/gcc/testsuite/gcc.dg/gnu2x-generic.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ + +_Static_assert(_Generic(const int, const int: 1, int: 0), ""); +_Static_assert(_Generic( int, const int: 0, int: 1), ""); +_Static_assert(_Generic(int[4], int[4]: 1), ""); +_Static_assert(_Generic(typeof(int[4]), int[4]: 1), ""); + +void foo(int n) +{ + _Static_assert(_Generic(int[n++], int[4]: 1), ""); +} + +#pragma GCC diagnostic warning "-Wpedantic" +_Static_assert(_Generic(int[4], int[4]: 1), ""); /* { dg-warning "extension" } */ + +