Viewing file: addr_builtin-1.C (8.41 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
// 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; } }
|