{ "typedef", RID_TYPEDEF, 0 },
{ "typename", RID_TYPENAME, D_CXXONLY | D_CXXWARN },
{ "typeid", RID_TYPEID, D_CXXONLY | D_CXXWARN },
- { "typeof", RID_TYPEOF, D_ASM | D_EXT },
+ { "typeof", RID_TYPEOF, D_EXT11 },
+ { "typeof_unqual", RID_TYPEOF_UNQUAL, D_CONLY | D_C2X },
{ "union", RID_UNION, 0 },
{ "unsigned", RID_UNSIGNED, 0 },
{ "using", RID_USING, D_CXXONLY | D_CXXWARN },
RID_SIZEOF,
/* C extensions */
- RID_ASM, RID_TYPEOF, RID_ALIGNOF, RID_ATTRIBUTE, RID_VA_ARG,
+ RID_ASM, RID_TYPEOF, RID_TYPEOF_UNQUAL, RID_ALIGNOF, RID_ATTRIBUTE,
+ RID_VA_ARG,
RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL, RID_CHOOSE_EXPR,
RID_TYPES_COMPATIBLE_P, RID_BUILTIN_COMPLEX, RID_BUILTIN_SHUFFLE,
RID_BUILTIN_SHUFFLEVECTOR, RID_BUILTIN_CONVERTVECTOR, RID_BUILTIN_TGMATH,
#define D_CXX11 0x0010 /* In C++, C++11 only. */
#define D_EXT 0x0020 /* GCC extension. */
#define D_EXT89 0x0040 /* GCC extension incorporated in C99. */
-#define D_ASM 0x0080 /* Disabled by -fno-asm. */
-#define D_OBJC 0x0100 /* In Objective C and neither C nor C++. */
-#define D_CXX_OBJC 0x0200 /* In Objective C, and C++, but not C. */
-#define D_CXXWARN 0x0400 /* In C warn with -Wcxx-compat. */
-#define D_CXX_CONCEPTS 0x0800 /* In C++, only with concepts. */
-#define D_TRANSMEM 0x1000 /* C++ transactional memory TS. */
-#define D_CXX_CHAR8_T 0x2000 /* In C++, only with -fchar8_t. */
-#define D_CXX20 0x4000 /* In C++, C++20 only. */
-#define D_CXX_COROUTINES 0x8000 /* In C++, only with coroutines. */
-#define D_CXX_MODULES 0x10000 /* In C++, only with modules. */
+#define D_EXT11 0x0080 /* GCC extension incorporated in C2X. */
+#define D_ASM 0x0100 /* Disabled by -fno-asm. */
+#define D_OBJC 0x0200 /* In Objective C and neither C nor C++. */
+#define D_CXX_OBJC 0x0400 /* In Objective C, and C++, but not C. */
+#define D_CXXWARN 0x0800 /* In C warn with -Wcxx-compat. */
+#define D_CXX_CONCEPTS 0x1000 /* In C++, only with concepts. */
+#define D_TRANSMEM 0x2000 /* C++ transactional memory TS. */
+#define D_CXX_CHAR8_T 0x4000 /* In C++, only with -fchar8_t. */
+#define D_CXX20 0x8000 /* In C++, C++20 only. */
+#define D_CXX_COROUTINES 0x10000 /* In C++, only with coroutines. */
+#define D_CXX_MODULES 0x20000 /* In C++, only with modules. */
#define D_CXX_CONCEPTS_FLAGS D_CXXONLY | D_CXX_CONCEPTS
#define D_CXX_CHAR8_T_FLAGS D_CXXONLY | D_CXX_CHAR8_T
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;
case RID_STRUCT:
case RID_UNION:
case RID_TYPEOF:
+ case RID_TYPEOF_UNQUAL:
case RID_CONST:
case RID_ATOMIC:
case RID_VOLATILE:
case RID_STRUCT:
case RID_UNION:
case RID_TYPEOF:
+ case RID_TYPEOF_UNQUAL:
case RID_CONST:
case RID_VOLATILE:
case RID_RESTRICT:
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? */
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++;
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;
}
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
case RID_ASM:
case RID_SIZEOF:
case RID_TYPEOF:
+ case RID_TYPEOF_UNQUAL:
case RID_ALIGNOF:
case RID_UNSIGNED:
case RID_LONG:
/* 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. */
&& 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. */
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. */
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;
}
if (!flag_char8_t)
mask |= D_CXX_CHAR8_T;
if (flag_no_asm)
- mask |= D_ASM | D_EXT;
+ mask |= D_ASM | D_EXT | D_EXT11;
if (flag_no_gnu_keywords)
- mask |= D_EXT;
+ mask |= D_EXT | D_EXT11;
/* The Objective-C keywords are all context-dependent. */
mask |= D_OBJC;
instead, which disables @code{typeof} but not @code{asm} and
@code{inline}. In C99 mode (@option{-std=c99} or @option{-std=gnu99}),
this switch only affects the @code{asm} and @code{typeof} keywords,
-since @code{inline} is a standard keyword in ISO C99.
+since @code{inline} is a standard keyword in ISO C99. In C2X mode
+(@option{-std=c2x} or @option{-std=gnu2x}), this switch only affects
+the @code{asm} keyword, since @code{typeof} is a standard keyword in
+ISO C2X.
@item -fno-builtin
@itemx -fno-builtin-@var{function}
--- /dev/null
+/* Test typeof and typeof_unqual not keywords in C11. */
+/* { dg-do compile } */
+/* { dg-options "-std=c11 -pedantic-errors" } */
+
+int typeof = 1;
+long typeof_unqual = 2;
--- /dev/null
+/* Test C2x typeof and typeof_unqual. Valid code. */
+/* { dg-do run } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+int i;
+extern typeof (i) i;
+extern typeof (int) i;
+extern typeof_unqual (i) i;
+extern typeof_unqual (int) i;
+
+volatile int vi;
+extern typeof (volatile int) vi;
+extern typeof (vi) vi;
+
+extern typeof_unqual (volatile int) i;
+extern typeof_unqual (vi) i;
+extern typeof ((const int) vi) i;
+extern typeof ((volatile int) vi) i;
+
+const int ci;
+extern typeof (const int) ci;
+extern typeof (ci) ci;
+
+extern typeof_unqual (const int) i;
+extern typeof_unqual (ci) i;
+extern typeof ((const int) ci) i;
+extern typeof (+ci) i;
+extern typeof (0, ci) i;
+extern typeof (1 ? ci : ci) i;
+extern typeof (0) i;
+
+const int fci (void);
+extern typeof (fci ()) i;
+
+_Atomic int ai;
+extern typeof (_Atomic int) ai;
+extern typeof (_Atomic (int)) ai;
+extern typeof (ai) ai;
+
+extern typeof_unqual (_Atomic int) i;
+extern typeof_unqual (_Atomic (int)) i;
+extern typeof_unqual (ai) i;
+extern typeof (+ai) i;
+extern typeof ((_Atomic int) ai) i;
+extern typeof (0, ai) i;
+extern typeof (1 ? ai : ai) i;
+
+_Atomic int fai (void);
+extern typeof (fai ()) i;
+
+_Atomic const volatile int acvi;
+extern typeof (int volatile const _Atomic) acvi;
+extern typeof (acvi) acvi;
+extern const _Atomic volatile typeof (acvi) acvi;
+extern _Atomic volatile typeof (ci) acvi;
+extern _Atomic const typeof (vi) acvi;
+extern const typeof (ai) volatile acvi;
+
+extern typeof_unqual (acvi) i;
+extern typeof_unqual (typeof (acvi)) i;
+extern typeof_unqual (_Atomic typeof_unqual (acvi)) i;
+
+extern _Atomic typeof_unqual (acvi) ai;
+
+char c;
+volatile char vc;
+volatile char *pvc;
+volatile char *const cpvc;
+const char *pcc;
+const char *volatile vpcc;
+typeof (*vpcc) cc;
+
+extern typeof (*cpvc) vc;
+extern typeof_unqual (*cpvc) c;
+extern typeof_unqual (cpvc) pvc;
+extern typeof_unqual (vpcc) pcc;
+extern const char cc;
+
+extern typeof (++vi) i;
+extern typeof (++ai) i;
+extern typeof (--vi) i;
+extern typeof (--ai) i;
+extern typeof (vi++) i;
+extern typeof (ai++) i;
+extern typeof (vi--) i;
+extern typeof (ai--) i;
+
+bool b;
+volatile bool vb;
+_Atomic bool ab;
+extern typeof (++vb) b;
+extern typeof (++ab) b;
+extern typeof (--vb) b;
+extern typeof (--ab) b;
+extern typeof (vb++) b;
+extern typeof (ab++) b;
+extern typeof (vb--) b;
+extern typeof (ab--) b;
+
+extern typeof (vc = 1) c;
+extern typeof (vpcc = 0) pcc;
+extern typeof (ai *= 2) i;
+
+int s = sizeof (typeof (int (*)[++i]));
+
+void *vp;
+
+/* The non-returning property of a function is not part of the type given by
+ ISO C typeof. */
+_Noreturn void nf1 (void);
+[[noreturn]] void nf2 (void);
+void fg (void) {}
+typeof (&nf1) pnf1 = fg;
+typeof (&nf2) pnf2 = fg;
+extern void (*pnf1) (void);
+extern void (*pnf2) (void);
+extern typeof (nf1) *pnf1;
+extern typeof (nf1) *pnf2;
+extern typeof (nf2) *pnf1;
+extern typeof (nf2) *pnf2;
+typeof (*&nf1) fg2, fg2a, fg2b;
+typeof (*&nf2) fg3, fg3a, fg3b;
+typeof (nf1) fg4, fg4a, fg4b;
+typeof (nf2) fg5, fg5a, fg5b;
+
+extern void abort (void);
+extern void exit (int);
+
+void fg2 (void) {}
+_Noreturn void fg2a (void) { abort (); }
+[[noreturn]] void fg2b (void) { abort (); }
+void fg3 (void) {}
+_Noreturn void fg3a (void) { abort (); }
+[[noreturn]] void fg3b (void) { abort (); }
+void fg4 (void) {}
+_Noreturn void fg4a (void) { abort (); }
+[[noreturn]] void fg4b (void) { abort (); }
+void fg5 (void) {}
+_Noreturn void fg5a (void) { abort (); }
+[[noreturn]] void fg5b (void) { abort (); }
+
+extern int only_used_in_typeof;
+
+static int not_defined (void);
+
+typeof (i)
+main (typeof (*vp))
+{
+ volatile typeof (only_used_in_typeof) ii = 2;
+ if (ii != 2)
+ abort ();
+ const typeof (not_defined ()) jj = 3;
+ if (jj != 3)
+ abort ();
+ unsigned int u = 1;
+ typeof (u) u2 = 0;
+ typeof (int (*)[++u2]) p = 0;
+ if (u2 != 1)
+ abort ();
+ if (sizeof (*p) != sizeof (int))
+ abort ();
+ typeof_unqual (int (*)[++u2]) q = 0;
+ if (u2 != 2)
+ abort ();
+ if (sizeof (*q) != 2 * sizeof (int))
+ abort ();
+ if (sizeof (*p) != sizeof (int))
+ abort ();
+ typeof (++u2) u3 = 1;
+ if (u2 != u + u3)
+ abort ();
+ typeof_unqual (++u2) u4 = 2;
+ if (u2 != u4)
+ abort ();
+ u = sizeof (typeof (int (*)[++u2]));
+ if (u2 != 2)
+ abort ();
+ u = sizeof (typeof_unqual (int (*)[++u2]));
+ if (u2 != 2)
+ abort ();
+ typeof ((int (*)[++u2]) 0) q2;
+ if (u2 != 3)
+ abort ();
+ typeof ((void) 0, (int (*)[++u2]) 0) q3;
+ if (u2 != 4)
+ abort ();
+ typeof ((int (*)[++u2]) 0, 0) q4;
+ if (u2 != 4)
+ abort ();
+ typeof_unqual ((int (*)[++u2]) 0) q5;
+ if (u2 != 5)
+ abort ();
+ typeof_unqual ((void) 0, (int (*)[++u2]) 0) q6;
+ if (u2 != 6)
+ abort ();
+ typeof_unqual ((int (*)[++u2]) 0, 0) q7;
+ if (u2 != 6)
+ abort ();
+ int a1[6], a2[6];
+ int (*pa)[u2] = &a1;
+ typeof (pa = &a2) pp;
+ if (pa != &a2)
+ abort ();
+ typeof_unqual (pa = &a1) pp2;
+ if (pa != &a1)
+ abort ();
+ exit (0);
+}
--- /dev/null
+/* Test C2x typeof and typeof_unqual. Invalid code. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors" } */
+
+struct s { int i : 2; } x;
+union u { unsigned int j : 1; } y;
+
+typeof (x.i) j; /* { dg-error "applied to a bit-field" } */
+typeof_unqual (x.i) j2; /* { dg-error "applied to a bit-field" } */
+typeof (y.j) j3; /* { dg-error "applied to a bit-field" } */
+typeof_unqual (y.j) j4; /* { dg-error "applied to a bit-field" } */
+
+static int ok (void);
+static int also_ok (void);
+static int not_defined (void); /* { dg-error "used but never defined" } */
+static int also_not_defined (void); /* { dg-error "used but never defined" } */
+
+void
+f (void)
+{
+ typeof (ok ()) x = 2;
+ typeof_unqual (also_ok ()) y = 2;
+ int a[2];
+ int (*p)[x] = &a;
+ typeof (p + not_defined ()) q;
+ typeof_unqual (p + also_not_defined ()) q2;
+}
--- /dev/null
+/* Test C2x typeof and typeof_unqual. -fno-asm has no effect on keywords in
+ C2x mode. */
+/* { dg-do compile } */
+/* { dg-options "-std=c2x -pedantic-errors -fno-asm" } */
+
+int i;
+extern typeof (i) i;
--- /dev/null
+/* Test typeof and typeof_unqual not keywords with -std=gnu11 -fno-asm. */
+/* { dg-do compile } */
+/* { dg-options "-std=gnu11 -fno-asm" } */
+
+int typeof = 1;
+long typeof_unqual = 2;
--- /dev/null
+/* Test typeof propagation of noreturn function attributes with -std=gnu11:
+ these are part of the type of a function pointer with GNU typeof, but not
+ with C2x typeof. */
+/* { dg-do link } */
+/* { dg-options "-std=gnu11 -O2" } */
+
+_Noreturn void f (void);
+
+typeof (&f) volatile p;
+typeof (&p) volatile pp;
+
+void link_failure (void);
+
+void
+g (void)
+{
+ (*p) ();
+ link_failure ();
+}
+
+void
+h (void)
+{
+ (**pp) ();
+ link_failure ();
+}
+
+volatile int flag;
+volatile int x;
+
+int
+main (void)
+{
+ if (flag)
+ g ();
+ if (flag)
+ h ();
+ return x;
+}
--- /dev/null
+/* Test __typeof__ propagation of noreturn function attributes with -std=gnu2x:
+ these are part of the type of a function pointer with GNU __typeof__, but
+ not with C2x typeof. */
+/* { dg-do link } */
+/* { dg-options "-std=gnu2x -O2" } */
+
+_Noreturn void f (void);
+
+__typeof__ (&f) volatile p;
+__typeof__ (&p) volatile pp;
+
+void link_failure (void);
+
+void
+g (void)
+{
+ (*p) ();
+ link_failure ();
+}
+
+void
+h (void)
+{
+ (**pp) ();
+ link_failure ();
+}
+
+volatile int flag;
+volatile int x;
+
+int
+main (void)
+{
+ if (flag)
+ g ();
+ if (flag)
+ h ();
+ return x;
+}