Commit 91f6ec2f by Martin Sebor Committed by Martin Sebor

PR c/66516 - missing diagnostic on taking the address of a builtin function

PR c/66516 - missing diagnostic on taking the address of a builtin function
	* g++.dg/addr_builtin-1.C: New test (accidentally omitted from
	initial commit).
	* gcc.dg/addr_builtin-1.c: Same.

From-SVN: r230916
parent 1ff9ed6f
2015-11-25 Martin Sebor <msebor@redhat.com>
PR c/66516
* g++.dg/addr_builtin-1.C: New test (left out of initial commit).
* gcc.dg/addr_builtin-1.c: Same.
2015-11-25 Michael Meissner <meissner@linux.vnet.ibm.com>
* gcc.target/powerpc/dform-1.c: New test.
......@@ -7943,12 +7949,6 @@
check the assembly.
* gcc.target/aarch64/arm_align_max_stack_pwr.c: Likewise.
2015-09-03 Martin Sebor <msebor@redhat.com>
PR c/66516
* g++.dg/addr_builtin-1.C: New test.
* gcc.dg/addr_builtin-1.c: New test.
2015-09-03 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
* gcc.target/powerpc/vec-shift.c: New test.
......
// 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 "invalid" }
a = static_cast<UINTPTR_E>(__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<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" }
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;
}
}
/* 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;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment