/* PR66516 - missing diagnostic on taking the address of a builtin function { dg-do compile } */ typedef void (F)(void); typedef __UINTPTR_TYPE__ uintptr_t; /* Utility function to test passing built-in functions as an ordinary argument and via the ellipsis. */ static void func_arg (F *p, ...) { (void)p; } static F* test_taking_address_of_gcc_builtin (void) { F *p; void *q; uintptr_t a; /* Call, cast to void, and id are allowed. */ __builtin_trap (); (void)__builtin_trap; __builtin_trap; { typedef __typeof__ (__builtin_trap) F; /* Okay. */ } /* Address and indirection operators. */ p = &__builtin_trap; /* { dg-error "built-in function" } */ p = *__builtin_trap; /* { dg-error "built-in function" } */ /* Unary NOT. */ a = !__builtin_trap; /* { dg-error "built-in function" } */ /* Sizeof and _Alignof are disallowed by C but allowed by GCC and there's no reason to reject built-ins as operands since doing so doesn't yield their address. */ #pragma GCC diagnostic push /* Disable: invalid application of 'sizeof' to a function type. */ #pragma GCC diagnostic ignored "-Wpointer-arith" a = sizeof __builtin_trap; #pragma GCC diagnostic pop #ifndef __STDC_VERSION__ # pragma GCC diagnostic push /* Disable: ISO C90 does not support '_Alignof'. */ # pragma GCC diagnostic ignored "-Wpedantic" #endif a = _Alignof __builtin_trap; #ifndef __STDC_VERSION__ # pragma GCC diagnostic pop #endif /* Casts. */ p = (F*)__builtin_trap; /* { dg-error "built-in function" } */ a = (uintptr_t)__builtin_trap; /* { dg-error "built-in function" } */ /* Additive operator. */ p = __builtin_trap + 0; /* { dg-error "built-in function" } */ p = __builtin_trap - 0; /* { dg-error "built-in function" } */ a = __builtin_trap - p; /* { dg-error "built-in function" } */ a = p - __builtin_trap; /* { dg-error "built-in function" } */ /* Relational operators. */ a = __builtin_trap < p; /* { dg-error "built-in function" } */ a = p < __builtin_trap; /* { dg-error "built-in function" } */ a = __builtin_trap <= p; /* { dg-error "built-in function" } */ a = p <= __builtin_trap; /* { dg-error "built-in function" } */ a = __builtin_trap > p; /* { dg-error "built-in function" } */ a = p > __builtin_trap; /* { dg-error "built-in function" } */ a = __builtin_trap > p; /* { dg-error "built-in function" } */ a = p > __builtin_trap; /* { dg-error "built-in function" } */ a = __builtin_trap <= p; /* { dg-error "built-in function" } */ a = p <= __builtin_trap; /* { dg-error "built-in function" } */ a = __builtin_trap <= p; /* { dg-error "built-in function" } */ a = p <= __builtin_trap; /* { dg-error "built-in function" } */ /* Equality operators. */ a = __builtin_trap == p; /* { dg-error "built-in function" } */ a = p == __builtin_trap; /* { dg-error "built-in function" } */ a = __builtin_trap != p; /* { dg-error "built-in function" } */ a = p != __builtin_trap; /* { dg-error "built-in function" } */ /* Logical AND and OR. */ a = __builtin_trap && p; /* { dg-error "built-in function" } */ a = p && __builtin_trap; /* { dg-error "built-in function" } */ a = __builtin_trap || p; /* { dg-error "built-in function" } */ a = p || __builtin_trap; /* { dg-error "built-in function" } */ /* Conditional operator. */ a = __builtin_trap ? 1 : 0; /* { dg-error "built-in function" } */ p = a ? __builtin_trap : 0; /* { dg-error "built-in function" } */ p = a ? 0 : __builtin_trap; /* { dg-error "built-in function" } */ /* Assignment operator. */ p = __builtin_trap; /* { dg-error "built-in function" } */ q = __builtin_trap; /* { dg-error "built-in function" } */ a = __builtin_trap; /* { dg-error "built-in function" } */ /* Passing as an argument. */ func_arg (__builtin_trap); /* { dg-error "built-in function" } */ /* Passing through the ellipsis. */ func_arg (0, __builtin_trap); /* { dg-error "built-in function" } */ /* Return statement. */ return __builtin_trap; /* { dg-error "built-in function" } */ (void)a; (void)p; (void)q; } /* Helper declarations to verify that it's possible to take the address of a user-declared function that's also a GCC built-in. */ extern int abs (int); extern __SIZE_TYPE__ strlen (const char*); /* Taking the address of a builtin with a library "fallback" must be allowed, either using the __builtin_xxx form or the xxx form, when the library fallback is declared either explicitly or implicitly by virtue of first calling the function. */ void test_taking_address_of_library_builtin (int i) { { typedef int F (int); /* Compute the address of libc's abs using the implicitly declared __builtin_abs form (all expressions are valid). */ F *p = __builtin_abs; p = &__builtin_abs; p = *__builtin_abs; /* Compute the address of libc's abs declared above. */ p = abs; p = &abs; p = *abs; (void)p; } { typedef __SIZE_TYPE__ size_t; typedef size_t F (const char*); /* Compute the address of libc's strlen using the implicitly declared __builtin_strlen form. */ F *p = __builtin_strlen; p = &__builtin_strlen; p = *__builtin_strlen; /* Compute the address of libc's strlen declared above. */ p = strlen; p = &strlen; p = *strlen; (void)p; } { typedef int F (int); /* Compute the address of libc's isxxx functions using the implicitly declared __builtin_xxx form. */ F *p = __builtin_isalnum; p = &__builtin_isalpha; p = *__builtin_iscntrl; /* According to C90 (see also the discussion in c/67386): If the expression that precedes the parenthesized argument list in a function call consists solely of an identifier, and if no declaration is visible for this identifier, the identifier is implicitly declared exactly as if, in the innermost block containing the function call, the declaration extern int identifier(); appeared. */ /* Call the functions first to have their declarations "injected" into the enclosing block. Suppress warnings. */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wimplicit-function-declaration" i = isalnum (i) || isalpha (i) || iscntrl (i); #pragma GCC diagnostic pop /* Take the address of the functions relying on their declarations having been implicitly provided by the calls above. */ p = isalnum; p = &isalpha; p = *iscntrl; (void)p; } }