forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			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, "");
 | |
| }
 |