aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2022-10-06 14:26:21 +0000
committerJoseph Myers <joseph@codesourcery.com>2022-10-06 14:26:21 +0000
commitfa258f6894801aef6785f0327594dc803da63fbd (patch)
treec11370ab02d3e2babc54547c0778057ce4a36e76 /gcc/c
parent09df0d8b14dda66c5159a1b2cf85b73f26282152 (diff)
downloadgcc-fa258f6894801aef6785f0327594dc803da63fbd.zip
gcc-fa258f6894801aef6785f0327594dc803da63fbd.tar.gz
gcc-fa258f6894801aef6785f0327594dc803da63fbd.tar.bz2
c: C2x typeof
C2x adds typeof as a standard feature. In general this follows existing GNU C semantics very closely, but there are various ways in which the implementation involves more than simply enabling the keyword for C2x: * As well as typeof, there is a typeof_unqual variant, which removes all qualifiers and _Atomic from the resulting type (whereas typeof preserves qualifiers and _Atomic on qualified or atomic (lvalue or type name) operands). * The typeof keyword is disabled by -fno-asm, so enabling it for C2x needs to be implemented in a way that preserves the disabling by -fno-asm for older standard versions (which having -fno-asm having no effect on it in C2x mode). This is done via adding a new D_EXT11 mask (which is also where the C++ front-end change comes from, to handle D_EXT11 appropriately there for -fno-asm and -fno-gnu-keywords). * GNU typeof treats the noreturn property of a function (as specified in standard C with _Noreturn or [[noreturn]]) as being part of the type of a pointer to function, but it is not part of the type in standard terms. Thus a special case is needed in the typeof implementation, just like in the _Generic implementation, to avoid treating it as a type for standard typeof. It seems plausible this is being used when copying the type of one object to another using typeof, so the existing semantics are preserved for __typeof__, and for typeof in pre-C2x modes, while typeof for C2x or later has the standard semantics. * It turns out that, even after Martin Uecker's changes in this area, there were still cases where rvalues could wrongly have a qualified or atomic type in GCC. This applied to ++ and -- increment and decrement expressions, and also to calls to functions returning an atomic type. (For the latter, the working draft doesn't actually explicitly exclude the function call expression having an atomic type, but given all the changes that have gone into C17 and C2x to avoid rvalues ever having qualified types, and given that lvalue-to-rvalue conversion removes both qualifiers and _Atomic, it seems unlikely that this (or casts, where GCC already removes _Atomic) is actually intended as a route to allow an _Atomic-qualified rvalue; I've noted this to raise as an NB comment on the CD ballot.) Bootstrapped with no regressions for x86_64-pc-linux-gnu. OK to commit (C+ gcc/ * doc/invoke.texi (-fno-asm): Update description of effects on typeof keyword. gcc/c-family/ * c-common.cc (c_common_reswords): Mark typeof as D_EXT11. Add typeof_unqual. * c-common.h (enum rid): Add RID_TYPEOF_UNQUAL. (D_EXT11): New macro. Values of subsequent macros updated. gcc/c/ * c-parser.cc (c_parse_init): Add D_EXT11 to mask if flag_no_asm and not C2x. (c_keyword_starts_typename, c_token_starts_declspecs) (c_parser_declspecs, c_parser_objc_selector): Handle RID_TYPEOF_UNQUAL. (c_parser_typeof_specifier): Handle RID_TYPEOF_UNQUAL. Distinguish typeof for C2x from __typeof__ for all standard versions and typeof before C2x. * c-typeck.cc (build_function_call_vec): Use unqualified version of non-void return type. (build_unary_op): Use unqualified type for increment and decrement. gcc/cp/ * lex.cc (init_reswords): Handle D_EXT11. gcc/testsuite/ * gcc.dg/c11-typeof-1.c, gcc.dg/c2x-typeof-1.c, gcc.dg/c2x-typeof-2.c, gcc.dg/c2x-typeof-3.c, gcc.dg/gnu11-typeof-1.c, gcc.dg/gnu11-typeof-2.c, gcc.dg/gnu2x-typeof-1.c: New tests.
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/c-parser.cc46
-rw-r--r--gcc/c/c-typeck.cc15
2 files changed, 53 insertions, 8 deletions
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 67b919c..89e0587 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -127,6 +127,8 @@ c_parse_init (void)
mask |= D_ASM | D_EXT;
if (!flag_isoc99)
mask |= D_EXT89;
+ if (!flag_isoc2x)
+ mask |= D_EXT11;
}
if (!c_dialect_objc ())
mask |= D_OBJC | D_CXX_OBJC;
@@ -580,6 +582,7 @@ c_keyword_starts_typename (enum rid keyword)
case RID_STRUCT:
case RID_UNION:
case RID_TYPEOF:
+ case RID_TYPEOF_UNQUAL:
case RID_CONST:
case RID_ATOMIC:
case RID_VOLATILE:
@@ -757,6 +760,7 @@ c_token_starts_declspecs (c_token *token)
case RID_STRUCT:
case RID_UNION:
case RID_TYPEOF:
+ case RID_TYPEOF_UNQUAL:
case RID_CONST:
case RID_VOLATILE:
case RID_RESTRICT:
@@ -3081,6 +3085,7 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
declspecs_add_type (loc, specs, t);
break;
case RID_TYPEOF:
+ case RID_TYPEOF_UNQUAL:
/* ??? The old parser rejected typeof after other type
specifiers, but is a syntax error the best way of
handling this? */
@@ -3768,22 +3773,38 @@ c_parser_struct_declaration (c_parser *parser)
return decls;
}
-/* Parse a typeof specifier (a GNU extension).
+/* Parse a typeof specifier (a GNU extension adopted in C2X).
typeof-specifier:
typeof ( expression )
typeof ( type-name )
+ typeof_unqual ( expression )
+ typeof_unqual ( type-name )
*/
static struct c_typespec
c_parser_typeof_specifier (c_parser *parser)
{
+ bool is_unqual;
+ bool is_std;
struct c_typespec ret;
ret.kind = ctsk_typeof;
ret.spec = error_mark_node;
ret.expr = NULL_TREE;
ret.expr_const_operands = true;
- gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF));
+ if (c_parser_next_token_is_keyword (parser, RID_TYPEOF))
+ {
+ is_unqual = false;
+ tree spelling = c_parser_peek_token (parser)->value;
+ is_std = (flag_isoc2x
+ && strcmp (IDENTIFIER_POINTER (spelling), "typeof") == 0);
+ }
+ else
+ {
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_TYPEOF_UNQUAL));
+ is_unqual = true;
+ is_std = true;
+ }
c_parser_consume_token (parser);
c_inhibit_evaluation_warnings++;
in_typeof++;
@@ -3825,6 +3846,24 @@ c_parser_typeof_specifier (c_parser *parser)
pop_maybe_used (was_vm);
}
parens.skip_until_found_close (parser);
+ if (ret.spec != error_mark_node)
+ {
+ if (is_unqual && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED)
+ ret.spec = TYPE_MAIN_VARIANT (ret.spec);
+ if (is_std)
+ {
+ /* 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 (TREE_CODE (ret.spec) == FUNCTION_TYPE
+ && TYPE_QUALS (ret.spec) != TYPE_UNQUALIFIED)
+ ret.spec = TYPE_MAIN_VARIANT (ret.spec);
+ else if (FUNCTION_POINTER_TYPE_P (ret.spec)
+ && TYPE_QUALS (TREE_TYPE (ret.spec)) != TYPE_UNQUALIFIED)
+ ret.spec
+ = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (ret.spec)));
+ }
+ }
return ret;
}
@@ -11961,7 +12000,7 @@ c_parser_objc_synchronized_statement (c_parser *parser)
identifier
one of
enum struct union if else while do for switch case default
- break continue return goto asm sizeof typeof __alignof
+ break continue return goto asm sizeof typeof typeof_unqual __alignof
unsigned long const short volatile signed restrict _Complex
in out inout bycopy byref oneway int char float double void _Bool
_Atomic
@@ -12001,6 +12040,7 @@ c_parser_objc_selector (c_parser *parser)
case RID_ASM:
case RID_SIZEOF:
case RID_TYPEOF:
+ case RID_TYPEOF_UNQUAL:
case RID_ALIGNOF:
case RID_UNSIGNED:
case RID_LONG:
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index ac242b5..f919068 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3187,6 +3187,7 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
/* fntype now gets the type of function pointed to. */
fntype = TREE_TYPE (fntype);
+ tree return_type = TREE_TYPE (fntype);
/* Convert the parameters to the types declared in the
function prototype, or apply default promotions. */
@@ -3203,8 +3204,6 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
&& TREE_CODE (tem = TREE_OPERAND (tem, 0)) == FUNCTION_DECL
&& !comptypes (fntype, TREE_TYPE (tem)))
{
- tree return_type = TREE_TYPE (fntype);
-
/* This situation leads to run-time undefined behavior. We can't,
therefore, simply error unless we can prove that all possible
executions of the program must execute the code. */
@@ -3229,22 +3228,25 @@ build_function_call_vec (location_t loc, vec<location_t> arg_loc,
bool warned_p = check_function_arguments (loc, fundecl, fntype,
nargs, argarray, &arg_loc);
+ if (TYPE_QUALS (return_type) != TYPE_UNQUALIFIED
+ && !VOID_TYPE_P (return_type))
+ return_type = c_build_qualified_type (return_type, TYPE_UNQUALIFIED);
if (name != NULL_TREE
&& startswith (IDENTIFIER_POINTER (name), "__builtin_"))
{
if (require_constant_value)
result
- = fold_build_call_array_initializer_loc (loc, TREE_TYPE (fntype),
+ = fold_build_call_array_initializer_loc (loc, return_type,
function, nargs, argarray);
else
- result = fold_build_call_array_loc (loc, TREE_TYPE (fntype),
+ result = fold_build_call_array_loc (loc, return_type,
function, nargs, argarray);
if (TREE_CODE (result) == NOP_EXPR
&& TREE_CODE (TREE_OPERAND (result, 0)) == INTEGER_CST)
STRIP_TYPE_NOPS (result);
}
else
- result = build_call_array_loc (loc, TREE_TYPE (fntype),
+ result = build_call_array_loc (loc, return_type,
function, nargs, argarray);
/* If -Wnonnull warning has been diagnosed, avoid diagnosing it again
later. */
@@ -4831,6 +4833,9 @@ build_unary_op (location_t location, enum tree_code code, tree xarg,
else
val = build2 (code, TREE_TYPE (arg), arg, inc);
TREE_SIDE_EFFECTS (val) = 1;
+ if (TYPE_QUALS (TREE_TYPE (val)) != TYPE_UNQUALIFIED)
+ TREE_TYPE (val) = c_build_qualified_type (TREE_TYPE (val),
+ TYPE_UNQUALIFIED);
ret = val;
goto return_build_unary_op;
}