blob: eebe54d316f06829a525b76803e54d9b4e8899bd [file] [log] [blame]
// PR66516 - missing diagnostic on taking the address of a builtin function
// { dg-do compile }
namespace std {
// Define type_info type to be able to use typeid in tests without
// having to include <typeinfo>.
struct type_info {
const char *name_;
explicit type_info (const char *s): name_ (s) { }
const char* name() const { return name_; }
};
}
// Extern "C" since builtin functions used in tests have C linkage.
extern "C" {
typedef void (F)();
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*, ...);
// Utility function with which, along with the built-in function,
// to instantiate the C98 multi-parameter or C11 variadic tempates
// below.
void f () { }
} // extern "C"
// Utility templates to test specializing templates on pointers and
// references to built-in functions.
template <F*> struct TestPointer { };
template <F&> struct TestReference { };
#if 201103 <= __cplusplus
template <F*...> struct TestPointers { };
template <F&...> struct TestReferences { };
#else
template <F* = &f, F* = &f> struct TestPointers { };
template <F& = f, F& = f> struct TestReferences { };
#endif
static F* test_taking_address_of_gcc_builtin ()
{
enum UINTPTR_E { e = ~(uintptr_t)0 };
F *p;
void *q;
uintptr_t a;
__builtin_trap (); // okay
(void)__builtin_trap; // okay
__builtin_trap; // okay (if pointless)
{
typedef __typeof__ (__builtin_trap) F; // okay
}
#if 201103 <= __cplusplus
{
typedef decltype (__builtin_trap) F; // okay
a = noexcept (&__builtin_trap);
}
#endif
// Address and indirection operators.
p = &__builtin_trap; // { dg-error "built-in" }
p = *__builtin_trap; // { dg-error "built-in" }
// Unary NOT.
// GCC issues two diagnostics here for some reason, so account for both.
a = !__builtin_trap; // { dg-error "built-in|unary" }
// Casts.
p = (F*)__builtin_trap; // { dg-error "built-in" }
p = &(F&)__builtin_trap; // { dg-error "built-in" }
p = &reinterpret_cast<F&>(__builtin_trap); // { dg-error "built-in" }
p = &static_cast<F&>(__builtin_trap); // { dg-error "built-in" }
p = reinterpret_cast<F*>(__builtin_trap); // { dg-error "built-in" }
p = static_cast<F*>(__builtin_trap); // { dg-error "built-in" }
// Expect a diagnostic for an invalid static_cast of a function to
// either uintptr_t or enum, rather than one for the argument being
// a built-in function, since the former is more relevant than the latter.
a = static_cast<uintptr_t>(__builtin_trap); // { dg-error "7:invalid .static_cast." }
a = static_cast<UINTPTR_E>(__builtin_trap); // { dg-error "7:invalid .static_cast." }
// Reinterpret cast can cast a function to uintptr_t or enum,
// so verify that a diagnostic is issued for the use of a builtin.
a = reinterpret_cast<uintptr_t>(__builtin_trap); // { dg-error "built-in" }
a = reinterpret_cast<UINTPTR_E>(__builtin_trap); // { dg-error "built-in" }
// Additive operator. Ill-formed but allowed with -fpermissive.
p = __builtin_trap + 0; // { dg-error "built-in" }
p = __builtin_trap - 0; // { dg-error "built-in" }
a = __builtin_trap - p; // { dg-error "built-in" }
a = p - __builtin_trap; // { dg-error "built-in" }
// Relational operators. Ill-formed but allowed with -fpermissive.
a = __builtin_trap < p; // { dg-error "built-in|invalid template-argument-list" }
a = p < __builtin_trap; // { dg-error "built-in" }
a = __builtin_trap <= p; // { dg-error "built-in" }
a = p <= __builtin_trap; // { dg-error "built-in" }
a = __builtin_trap > p; // { dg-error "built-in" }
a = p > __builtin_trap; // { dg-error "built-in" }
a = __builtin_trap > p; // { dg-error "built-in" }
a = p > __builtin_trap; // { dg-error "built-in" }
a = __builtin_trap <= p; // { dg-error "built-in" }
a = p <= __builtin_trap; // { dg-error "built-in" }
a = __builtin_trap <= p; // { dg-error "built-in" }
a = p <= __builtin_trap; // { dg-error "built-in" }
// Equality operators.
a = __builtin_trap == p; // { dg-error "built-in" }
a = p == __builtin_trap; // { dg-error "built-in" }
a = __builtin_trap != p; // { dg-error "built-in" }
a = p != __builtin_trap; // { dg-error "built-in" }
// Logical AND and OR.
a = __builtin_trap && p; // { dg-error "built-in" }
a = p && __builtin_trap; // { dg-error "built-in" }
a = __builtin_trap || p; // { dg-error "built-in" }
a = p || __builtin_trap; // { dg-error "built-in" }
// Conditional operator.
a = __builtin_trap ? 1 : 0; // { dg-error "built-in" }
p = a ? __builtin_trap : 0; // { dg-error "built-in" }
p = a ? 0 : __builtin_trap; // { dg-error "built-in" }
// Assignment operator.
p = __builtin_trap; // { dg-error "built-in" }
// Passing as an argument.
func_arg (__builtin_trap); // { dg-error "built-in" }
func_arg (&__builtin_trap); // { dg-error "built-in" }
func_arg (*__builtin_trap); // { dg-error "built-in" }
// Passing through ellipsis.
func_arg (0, __builtin_trap); // { dg-error "built-in" }
func_arg (0, &__builtin_trap); // { dg-error "built-in" }
func_arg (0, *__builtin_trap); // { dg-error "built-in" }
{
// Template specialization.
// GCC issues two diagnostics and we must account for both.
TestPointer<__builtin_trap> tp; // { dg-error "built-in|could not convert" }
TestReference<__builtin_trap> tr; // { dg-error "built-in|could not convert" }
TestPointers<__builtin_trap> tp1; // { dg-error "built-in|could not convert" }
TestReferences<__builtin_trap> tr1; // { dg-error "built-in|could not convert" }
TestPointers<f, __builtin_trap> tp2; // { dg-error "built-in|could not convert" }
TestReferences<f, __builtin_trap> tr2; // { dg-error "built-in|could not convert" }
TestPointers<__builtin_trap, f> tp3; // { dg-error "built-in|could not convert" }
TestReferences<__builtin_trap, f> tr3; // { dg-error "built-in|could not convert" }
}
try {
throw __builtin_trap; // { dg-error "built-in" }
}
catch (F) { }
return __builtin_trap; // { dg-error "built-in" }
(void)a;
(void)p;
(void)q;
}
// Make sure operators new and delete don't trigger false positives
// (they return true from DECL_IS_BUILTIN(DECL) -- see tree.h).
void test_taking_address_of_op_new_and_delete ()
{
typedef __SIZE_TYPE__ size_t;
typedef void* (OpNew) (size_t);
typedef void (OpDelete) (void*);
OpNew &newr = operator new;
OpNew &newra = operator new[];
OpNew *newp = &operator new;
newp = &operator new[];
OpDelete &delr = operator delete;
OpDelete &delra = operator delete[];
OpDelete *delp = &operator delete;
delp = &operator delete[];
(void)newr;
(void)newra;
(void)newp;
(void)delr;
(void)delra;
(void)delp;
}
// Helper declaration 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);
typedef __SIZE_TYPE__ size_t;
extern size_t strlen (const char*);
// Creating a reference to or taking the address of a built-in with
// a library "fallback" must be allowed.
void test_taking_address_of_library_builtin ()
{
{
typedef int F (int);
F &r1 = __builtin_abs;
F &r2 = *__builtin_abs;
F *p = __builtin_abs;
p = &__builtin_abs;
p = *__builtin_abs;
(void)p;
(void)r1;
(void)r2;
}
{
typedef int F (int);
F &r1 = abs;
F &r2 = *abs;
F *p = abs;
p = &abs;
p = *abs;
(void)p;
(void)r1;
(void)r2;
}
{
typedef __SIZE_TYPE__ size_t;
typedef size_t F (const char*);
F &r1 = __builtin_strlen;
F &r2 = *__builtin_strlen;
F *p = __builtin_strlen;
p = &__builtin_strlen;
p = *__builtin_strlen;
(void)p;
(void)r1;
(void)r2;
}
{
typedef size_t F (const char*);
F &r1 = strlen;
F &r2 = *strlen;
F *p = strlen;
p = &strlen;
p = *strlen;
(void)p;
(void)r1;
(void)r2;
}
}