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
This commit is contained in:
parent
1ff9ed6fb2
commit
91f6ec2fc6
3 changed files with 480 additions and 6 deletions
|
@ -1,3 +1,9 @@
|
|||
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.
|
||||
|
|
276
gcc/testsuite/g++.dg/addr_builtin-1.C
Normal file
276
gcc/testsuite/g++.dg/addr_builtin-1.C
Normal file
|
@ -0,0 +1,276 @@
|
|||
// 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;
|
||||
}
|
||||
}
|
198
gcc/testsuite/gcc.dg/addr_builtin-1.c
Normal file
198
gcc/testsuite/gcc.dg/addr_builtin-1.c
Normal file
|
@ -0,0 +1,198 @@
|
|||
/* 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;
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue