// 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 . 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 struct TestPointer { }; template struct TestReference { }; #if 201103 <= __cplusplus template struct TestPointers { }; template struct TestReferences { }; #else template struct TestPointers { }; template 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(__builtin_trap); // { dg-error "built-in" } p = &static_cast(__builtin_trap); // { dg-error "built-in" } p = reinterpret_cast(__builtin_trap); // { dg-error "built-in" } p = static_cast(__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(__builtin_trap); // { dg-error "invalid" } a = static_cast(__builtin_trap); // { dg-error "invalid" } // 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(__builtin_trap); // { dg-error "built-in" } a = reinterpret_cast(__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" } 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 tp2; // { dg-error "built-in|could not convert" } TestReferences 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; } }