view gcc/testsuite/g++.dg/cpp1y/constexpr-sfinae.C @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children
line wrap: on
line source

// Test exercising SFINAE depending on the well-definedness of constexpr
// functions.
// { dg-do compile { target c++14 } }

#define Assert(e) static_assert ((e), #e)

// Exercise SFINAE based on the absence of integer division by zero.
namespace DivByZero {

// Define a pair of functions that have undefined and well-defined
// behavior, respectively, due to division by zero, depending on
// their arguments.

// The following function is undefined when I is zero, well defined
// otherwise.
constexpr bool div_zero_0 (int i, int j) { return 1 + j / (i == 0); }

// The following function is undefined when I is non-zero, and well
// defined otherwise.
constexpr bool div_zero_1 (int i, int j) { return 1 + j / (i != 0); }

// Define a pair of overfloads each of which is viable when the constexpr
// function it invokes has well-defined semantics and not otherwise.
template <int I>
constexpr int f (int (*)[div_zero_0 (I, 0)] = 0) { return 0; }

template <int I>
constexpr int f (int (*)[div_zero_1 (I, 0)] = 0) { return 1; }

// Verify that the correct overload is selected based on the template
// argument and without triggering a compilation error for the undefined
// behavior in the non-viable constexpr function above.
Assert (f<0>() == 0);
Assert (f<1>() == 1);

}

// Exercise SFINAE based on the absence of signed integer overflow
// in addition.
namespace IntAddOverflow {

constexpr int a [] = { 1234, __INT_MAX__ / 2 };

constexpr int vflow_0 (int i) { return a [!i] * 7; }
constexpr int vflow_1 (int i) { return a [i] * 11; }

template <int I>
constexpr int f (int (*)[vflow_0 (I)] = 0) { return 1; }

template <int I>
constexpr int f (int (*)[vflow_1 (I)] = 0) { return 0; }

constexpr int n0 = f<0>();
constexpr int n1 = f<1>();

Assert (n0 == 0);
Assert (n1 == 1);

}

// Exercise SFINAE based on the absence of signed integer overflow
// in multiplication.
namespace IntMulOverflow {

constexpr long a [] = { 1234, __LONG_MAX__ / 2 };

constexpr long vflow_0 (int i) { return a [!i] * 3; }
constexpr long vflow_1 (int i) { return a [i] * 7; }

template <int I>
constexpr int f (int (*)[vflow_0 (I)] = 0) { return 1; }

template <int I>
constexpr int f (int (*)[vflow_1 (I)] = 0) { return 0; }

constexpr int n0 = f<0>();
constexpr int n1 = f<1>();

Assert (n0 == 0);
Assert (n1 == 1);

}

// Exercise SFINAE based on the absence of undefined pointer arithmetic
// involving null pointers.  Subtracting one null pointer from another
// is well-defined, but subtracting a null pointer from a non-null one
// is not.
namespace NullPointerArithmetic {

constexpr int i = 0;
constexpr const int* a[] = { 0, &i };

// Well-defined core constant expressions involving null pointers.
constexpr __PTRDIFF_TYPE__ d00 = a [0] - a [0];
constexpr __PTRDIFF_TYPE__ d11 = a [1] - a [1];

// Undefined core constant expressions involving null pointers.
// constexpr __PTRDIFF_TYPE__ d01 = a [0] - a [1];
// constexpr __PTRDIFF_TYPE__ d10 = a [1] - a [0];

// Valid when i == j.
constexpr bool
nullptr_sub_0 (bool i, bool j) { return 1 + a [!i] - a [!j]; }

// Valid when i != j.
constexpr bool
nullptr_sub_1 (bool i, bool j) { return 1 + a [i] - a [!j]; }

// Selected when I == 0.
template <bool I>
constexpr int f (int (*)[nullptr_sub_0 (I, 0)] = 0) { return 0; }

// Selected when I != 0.
template <bool I>
constexpr int f (int (*)[nullptr_sub_1 (I, 0)] = 0) { return 1; }

constexpr int n0 = f<0>();
constexpr int n1 = f<1>();

Assert (n0 == 0);
Assert (n1 == 1);

}

// Exercise SFINAE based on the absence of undefined pointer arithmetic
// involving null poiinters.  Subtracting one null pointer from another
// is well-defined, but subtracting a null pointer from a non-null one
// is not.
namespace NullPointerDereference {

struct S { int a, b; };

constexpr S s = { };
constexpr const S* a[] = { 0, &s };

constexpr bool nullptr_ref_0 (int i) { return &a [i != 0]->b == &s.b; }
constexpr bool nullptr_ref_1 (int i) { return &a [i == 0]->b == &s.b; }

template <int I>
constexpr int f (int (*)[nullptr_ref_0 (I)] = 0) { return 1; }

template <int I>
constexpr int f (int (*)[nullptr_ref_1 (I)] = 0) { return 0; }

constexpr int n0 = f<0>();
constexpr int n1 = f<1>();

Assert (n0 == 0);
Assert (n1 == 1);

}

// Exercise SFINAE based on whether or not two constexpr function
// calls have a circular depency on one another such that a call
// to one would not terminate.
namespace CircularDependency {

constexpr bool call_me (int i, bool (*f)(int)) { return f (i); }

constexpr bool undefined_if_0 (int i) {
    return i ? 1 : call_me (i, undefined_if_0);
}

constexpr bool undefined_if_1 (int i) {
    return i ? call_me (i, undefined_if_1) : 1;
}

template <int I>
constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }

template <int I>
constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }

constexpr int n0 = f<0>();
constexpr int n1 = f<1>();

Assert (n0 == 1);
Assert (n1 == 0);

}

// Exercise SFINAE based on whether constexpr functions flow off
// the end without returning a value.
namespace FlowOffTheEnd {

constexpr bool undefined_if_0 (int i) { switch (i) case 1: return 1; }
constexpr bool undefined_if_1 (int i) { switch (i) case 0: return 1; }

template <int I>
constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 1; }

template <int I>
constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 0; }

constexpr int n0 = f<0>();
constexpr int n1 = f<1>();

Assert (n0 == 0);
Assert (n1 == 1);

}

// Exercise SFINAE based on the presence and absence of a left shift
// expression with a negative second operand.
namespace NegativeLeftShift {

constexpr int a [] = { -1, 1 };

constexpr int undefined_if_0 (int i) { return 1 << a [i]; }
constexpr int undefined_if_1 (int i) { return 1 << a [!i]; }

template <int I>
constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }

template <int I>
constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }

constexpr int n0 = f<0>();
constexpr int n1 = f<1>();

Assert (n0 == 1);
Assert (n1 == 0);

}

// Exercise SFINAE based on the presence and absence of a right shift
// expression with a negative second operand.
namespace NegativeRightShift {

constexpr int a [] = { -1, 1 };

constexpr int undefined_if_0 (int i) { return 2 >> a [i]; }
constexpr int undefined_if_1 (int i) { return 2 >> a [!i]; }

template <int I>
constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }

template <int I>
constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }

constexpr int n0 = f<0>();
constexpr int n1 = f<1>();

Assert (n0 == 1);
Assert (n1 == 0);

}

// Exercise SFINAE based on the absence of signed integer overflow
// in a signed left shift expression.
namespace LeftShiftOverflow {

constexpr int a[] = { 1234, 1 };

constexpr int undefined_if_0 (int i) { return 1 << a [i]; }
constexpr int undefined_if_1 (int i) { return 1 << a [!i]; }

template <int I>
constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }

template <int I>
constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }

constexpr int n0 = f<0>();
constexpr int n1 = f<1>();

Assert (n0 == 1);
Assert (n1 == 0);

}

// Exercise SFINAE based on the absence of using a negative array
// index.
namespace NegativeArrayIndex {

constexpr int a [] = { -1, 1 };

constexpr int undefined_if_0 (int i) { return 2 + a [a [i]]; }
constexpr int undefined_if_1 (int i) { return 2 + a [a [!i]]; }

template <int I>
constexpr int f (int (*)[undefined_if_0 (I)] = 0) { return 0; }

template <int I>
constexpr int f (int (*)[undefined_if_1 (I)] = 0) { return 1; }

constexpr int n0 = f<0>();
constexpr int n1 = f<1>();

Assert (n0 == 1);
Assert (n1 == 0);

}