// { dg-do compile }
// { dg-options "-O1" }
// { dg-final { scan-assembler-not "abort" } }
typedef __SIZE_TYPE__ size_t;
extern "C" {
    void abort ();
    void* malloc (size_t);
}
struct UDClass {
    static int n;
    UDClass () { ++n; }
    virtual ~UDClass () { --n; }
};
int UDClass::n;
struct POD {
    char buf [sizeof (UDClass)];
};
enum { N = 123 };
#if defined (__arm__) && defined (__ARM_EABI__)
// On ARM EABI the cookie is always 8 bytes as per Section 3.2.2 of
// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0041d/IHI0041D_cppabi.pdf
static const size_t cookie_size = 8;
#else
// On all other targets, the cookie size is the size of size_t
// GCC, and ideally the C++ standard, should provide an API to
// retrieve this constant.)
static const size_t cookie_size = sizeof (size_t);
#endif
inline __attribute__ ((always_inline))
void* operator new[] (size_t n)
{
    // Verify that array new is invoked with an argument large enough
    // for the array and a size_t cookie to store the number of elements.
    // (This holds for classes with user-defined types but not POD types).
 
  if (n != N * sizeof (UDClass) + cookie_size) abort ();
    return malloc (n);
}
inline __attribute__ ((always_inline))
void* operator new[] (size_t n, void *p)
{
    // Verify that the default placement array new is invoked with
    // an argument just large enough for the array (and no cookie),
    // regardless of whether the type is a POD or class with a user
    // defined ctor.
    if (n != N * sizeof (UDClass)) abort ();
    return p;
}
inline __attribute__ ((always_inline))
void* operator new[] (size_t n, POD *p)
{
    // Verify that placement array new overload for a POD type is
    // invoked with an argument large enough for the array and
    // a cookie.
    if (n != N * sizeof (POD)) abort ();
    return p;
}
inline __attribute__ ((always_inline))
void* operator new[] (size_t n, UDClass *p)
{
    // Verify that placement array new overload for a class type with
    // a user-defined ctor and dtor is invoked with an argument large
    // enough for the array and a cookie.
    if (n != N * sizeof (UDClass) + cookie_size) abort ();
    return p;
}
// UDClassllocate a sufficiently large buffer to construct arrays into.
static unsigned char buf [N * N];
POD* test_new_POD ()
{
    // Avoid testing PODs since for those, the global new is invoked
    // without the overhead of a cookie.
    // return new POD [N];
    return 0;
}
POD* test_default_placement_new_POD ()
{
    // Vefify that no overhead is allocated.
    return new (buf) POD [N];
}
POD* test_overloaded_placement_new_POD ()
{
    // Vefify that no overhead is allocated.
    return new ((POD*)buf) POD [N];
}
UDClass* test_new_UDClass ()
{
    // Vefify that space for a cookie is allocated.
    return new UDClass [N];
}
UDClass* test_default_placement_new_UDClass ()
{
    // Vefify that no overhead is allocated.
    return new (buf) UDClass [N];
}
UDClass* test_overloaded_placement_new_UDClass ()
{
    // Vefify that space for a cookie is allocated.
    return new ((UDClass*)buf) UDClass [N];
}