262 lines
7.8 KiB
C++
262 lines
7.8 KiB
C++
// RUN: %clang_cc1 -std=c++11 -verify %s
|
|
|
|
namespace UseBeforeDefinition {
|
|
struct A {
|
|
template<typename T> static constexpr T get() { return T(); }
|
|
// ok, not a constant expression.
|
|
int n = get<int>();
|
|
};
|
|
|
|
// ok, constant expression.
|
|
constexpr int j = A::get<int>();
|
|
|
|
template<typename T> constexpr int consume(T);
|
|
// ok, not a constant expression.
|
|
const int k = consume(0); // expected-note {{here}}
|
|
|
|
template<typename T> constexpr int consume(T) { return 0; }
|
|
// ok, constant expression.
|
|
constexpr int l = consume(0);
|
|
|
|
constexpr int m = k; // expected-error {{constant expression}} expected-note {{initializer of 'k'}}
|
|
}
|
|
|
|
namespace IntegralConst {
|
|
template<typename T> constexpr T f(T n) { return n; }
|
|
enum E {
|
|
v = f(0), w = f(1) // ok
|
|
};
|
|
static_assert(w == 1, "");
|
|
|
|
char arr[f('x')]; // ok
|
|
static_assert(sizeof(arr) == 'x', "");
|
|
}
|
|
|
|
namespace ConvertedConst {
|
|
template<typename T> constexpr T f(T n) { return n; }
|
|
int f() {
|
|
switch (f()) {
|
|
case f(4): return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
namespace OverloadResolution {
|
|
template<typename T> constexpr T f(T t) { return t; }
|
|
|
|
template<int n> struct S { };
|
|
|
|
template<typename T> auto g(T t) -> S<f(sizeof(T))> &;
|
|
char &f(...);
|
|
|
|
template<typename T> auto h(T t[f(sizeof(T))]) -> decltype(&*t) {
|
|
return t;
|
|
}
|
|
|
|
S<4> &k = g(0);
|
|
int *p, *q = h(p);
|
|
}
|
|
|
|
namespace DataMember {
|
|
template<typename T> struct S { static const int k; };
|
|
const int n = S<int>::k; // expected-note {{here}}
|
|
template<typename T> const int S<T>::k = 0;
|
|
constexpr int m = S<int>::k; // ok
|
|
constexpr int o = n; // expected-error {{constant expression}} expected-note {{initializer of 'n'}}
|
|
}
|
|
|
|
namespace Reference {
|
|
const int k = 5;
|
|
template<typename T> struct S {
|
|
static volatile int &r;
|
|
};
|
|
template<typename T> volatile int &S<T>::r = const_cast<volatile int&>(k);
|
|
constexpr int n = const_cast<int&>(S<int>::r);
|
|
static_assert(n == 5, "");
|
|
}
|
|
|
|
namespace Unevaluated {
|
|
// We follow the current proposed resolution of core issue 1581: a constexpr
|
|
// function template specialization requires a definition if:
|
|
// * it is odr-used, or would be odr-used except that it appears within the
|
|
// definition of a template, or
|
|
// * it is used within a braced-init-list, where it may be necessary for
|
|
// detecting narrowing conversions.
|
|
//
|
|
// We apply this both for instantiating constexpr function template
|
|
// specializations and for implicitly defining defaulted constexpr special
|
|
// member functions.
|
|
//
|
|
// FIXME: None of this is required by the C++ standard yet. The rules in this
|
|
// area are subject to change.
|
|
namespace NotConstexpr {
|
|
template<typename T> struct S {
|
|
S() : n(0) {}
|
|
S(const S&) : n(T::error) {}
|
|
int n;
|
|
};
|
|
struct U : S<int> {};
|
|
decltype(U(U())) u;
|
|
}
|
|
namespace Constexpr {
|
|
template<typename T> struct S {
|
|
constexpr S() : n(0) {}
|
|
constexpr S(const S&) : n(T::error) {}
|
|
int n;
|
|
};
|
|
struct U : S<int> {};
|
|
decltype(U(U())) u;
|
|
}
|
|
namespace ConstexprList {
|
|
template<int N> struct S {
|
|
constexpr S() : n(0) {
|
|
static_assert(N >= 0, "");
|
|
}
|
|
constexpr operator int() const { return 0; }
|
|
int n;
|
|
};
|
|
struct U : S<0> {};
|
|
// ok, trigger instantiation within a list
|
|
decltype(char{U()}) t0;
|
|
decltype(new char{S<1>()}) t1; // expected-warning {{side effects}}
|
|
decltype((char){S<2>()}) t2;
|
|
decltype(+(char[1]){{S<3>()}}) t3;
|
|
// do not trigger instantiation outside a list
|
|
decltype(char(S<-1>())) u1;
|
|
decltype(new char(S<-2>())) u2; // expected-warning {{side effects}}
|
|
decltype((char)(S<-3>())) u3;
|
|
}
|
|
|
|
namespace PR11851_Comment0 {
|
|
template<int x> constexpr int f() { return x; }
|
|
template<int i> void ovf(int (&x)[f<i>()]);
|
|
void f() { int x[10]; ovf<10>(x); }
|
|
}
|
|
|
|
namespace PR11851_Comment1 {
|
|
template<typename T>
|
|
constexpr bool Integral() {
|
|
return true;
|
|
}
|
|
template<typename T, bool Int = Integral<T>()>
|
|
struct safe_make_unsigned {
|
|
typedef T type;
|
|
};
|
|
template<typename T>
|
|
using Make_unsigned = typename safe_make_unsigned<T>::type;
|
|
template <typename T>
|
|
struct get_distance_type {
|
|
using type = int;
|
|
};
|
|
template<typename R>
|
|
auto size(R) -> Make_unsigned<typename get_distance_type<R>::type>;
|
|
auto check() -> decltype(size(0));
|
|
}
|
|
|
|
namespace PR11851_Comment6 {
|
|
template<int> struct foo {};
|
|
template<class> constexpr int bar() { return 0; }
|
|
template<class T> foo<bar<T>()> foobar();
|
|
auto foobar_ = foobar<int>();
|
|
}
|
|
|
|
namespace PR11851_Comment9 {
|
|
struct S1 {
|
|
constexpr S1() {}
|
|
constexpr operator int() const { return 0; }
|
|
};
|
|
int k1 = sizeof(short{S1(S1())});
|
|
|
|
struct S2 {
|
|
constexpr S2() {}
|
|
constexpr operator int() const { return 123456; }
|
|
};
|
|
int k2 = sizeof(short{S2(S2())}); // expected-error {{cannot be narrowed}} expected-note {{insert an explicit cast to silence this issue}}
|
|
}
|
|
|
|
namespace PR12288 {
|
|
template <typename> constexpr bool foo() { return true; }
|
|
template <bool> struct bar {};
|
|
template <typename T> bar<foo<T>()> baz() { return bar<foo<T>()>(); }
|
|
int main() { baz<int>(); }
|
|
}
|
|
|
|
namespace PR13423 {
|
|
template<bool, typename> struct enable_if {};
|
|
template<typename T> struct enable_if<true, T> { using type = T; };
|
|
|
|
template<typename T> struct F {
|
|
template<typename U>
|
|
static constexpr bool f() { return sizeof(T) < U::size; }
|
|
|
|
template<typename U>
|
|
static typename enable_if<f<U>(), void>::type g() {} // expected-note {{requirement 'f<Unevaluated::PR13423::U>()' was not satisfied}}
|
|
};
|
|
|
|
struct U { static constexpr int size = 2; };
|
|
|
|
void h() { F<char>::g<U>(); }
|
|
void i() { F<int>::g<U>(); } // expected-error {{no matching function}}
|
|
}
|
|
|
|
namespace PR14203 {
|
|
struct duration { constexpr duration() {} };
|
|
|
|
template <typename>
|
|
void sleep_for() {
|
|
constexpr duration max = duration();
|
|
}
|
|
}
|
|
|
|
// For variables, we instantiate when they are used in a context in which
|
|
// evaluation could be required (odr-used, used in a template whose
|
|
// instantiations would odr-use, or used in list initialization), if they
|
|
// can be used as a constant (const integral or constexpr).
|
|
namespace Variables {
|
|
template<int N> struct A {
|
|
static const int k;
|
|
static int n;
|
|
};
|
|
template<const int *N> struct B {};
|
|
template<int N> constexpr int A<N>::k = *(int[N]){N}; // expected-error 1+{{negative}}
|
|
template<int N> int A<N>::n = *(int[N]){0};
|
|
|
|
template <typename> void f() {
|
|
(void)A<-1>::n; // ok
|
|
(void)A<-1>::k; // expected-note {{instantiation of }}
|
|
B<&A<-2>::n> b1; // ok
|
|
B<&A<-2>::k> b2; // expected-note {{instantiation of }}
|
|
};
|
|
|
|
decltype(A<-3>::k) d1 = 0; // ok
|
|
decltype(char{A<-4>::k}) d2 = 0; // expected-note {{instantiation of }} expected-error {{narrow}} expected-note {{cast}}
|
|
decltype(char{A<1>::k}) d3 = 0; // ok
|
|
decltype(char{A<1 + (unsigned char)-1>::k}) d4 = 0; // expected-error {{narrow}} expected-note {{cast}}
|
|
}
|
|
}
|
|
|
|
namespace NoInstantiationWhenSelectingOverload {
|
|
// Check that we don't instantiate conversion functions when we're checking
|
|
// for the existence of an implicit conversion sequence, only when a function
|
|
// is actually chosen by overload resolution.
|
|
struct S {
|
|
template<typename T> constexpr S(T) : n(T::error) {} // expected-error {{no members}}
|
|
int n;
|
|
};
|
|
|
|
constexpr int f(S) { return 0; }
|
|
constexpr int f(int) { return 0; }
|
|
|
|
void g() { f(0); }
|
|
void h() { (void)sizeof(char{f(0)}); }
|
|
void i() { (void)sizeof(char{f("oops")}); } // expected-note {{instantiation of}}
|
|
}
|
|
|
|
namespace PR20090 {
|
|
template <typename T> constexpr T fact(T n) {
|
|
return n == 0 ? 1 : [=] { return n * fact(n - 1); }();
|
|
}
|
|
static_assert(fact(0) == 1, "");
|
|
}
|