Saar Raz c83d9bedc0 [Concept] Fix incorrect check for containsUnexpandedParameterPack in CSE
We previously checked for containsUnexpandedParameterPack in CSEs by observing the property
in the converted arguments of the CSE. This may not work if the argument is an expanded
type-alias that contains a pack-expansion (see added test).

Check the as-written arguments when determining containsUnexpandedParameterPack and isInstantiationDependent.
2020-01-30 20:45:44 +02:00

201 lines
6.3 KiB
C++

// RUN: %clang_cc1 -std=c++2a -verify -triple x86_64-linux-gnu %s
template<typename T> concept C1 = true; // expected-note{{template is declared here}}
static_assert(C1<int>);
static_assert(C1);
// expected-error@-1{{use of concept 'C1' requires template arguments}}
template<typename T> concept C2 = sizeof(T) == 4;
static_assert(C2<int>);
static_assert(!C2<long long int>);
static_assert(C2<char[4]>);
static_assert(!C2<char[5]>);
template<typename T> concept C3 = sizeof(*T{}) == 4;
static_assert(C3<int*>);
static_assert(!C3<long long int>);
struct A {
static constexpr int add(int a, int b) {
return a + b;
}
};
struct B {
static int add(int a, int b) { // expected-note{{declared here}}
return a + b;
}
};
template<typename U>
concept C4 = U::add(1, 2) == 3;
// expected-error@-1{{substitution into constraint expression resulted in a non-constant expression}}
// expected-note@-2{{non-constexpr function 'add' cannot be used in a constant expression}}
static_assert(C4<A>);
static_assert(!C4<B>); // expected-note {{while checking the satisfaction of concept 'C4<B>' requested here}}
template<typename T, typename U>
constexpr bool is_same_v = false;
template<typename T>
constexpr bool is_same_v<T, T> = true;
template<typename T, typename U>
concept Same = is_same_v<T, U>;
static_assert(Same<int, int>);
static_assert(Same<int, decltype(1)>);
static_assert(!Same<int, unsigned int>);
static_assert(!Same<A, B>);
static_assert(Same<A, A>);
static_assert(Same<bool, decltype(C1<int>)>);
static_assert(Same<bool, decltype(C2<int>)>);
static_assert(Same<bool, decltype(C3<int*>)>);
static_assert(Same<bool, decltype(C4<A>)>);
template<typename T> concept C5 = T{}; // expected-error {{atomic constraint must be of type 'bool' (found 'int')}}
constexpr bool x = C5<int>; // expected-note {{while checking the satisfaction of concept 'C5<int>' requested here}}
template<int x>
concept IsEven = (x % 2) == 0;
static_assert(IsEven<20>);
static_assert(!IsEven<11>);
template<template<typename T> typename P>
concept IsTypePredicate = is_same_v<decltype(P<bool>::value), const bool>
&& is_same_v<decltype(P<int>::value), const bool>
&& is_same_v<decltype(P<long long>::value), const bool>;
template<typename T> struct T1 {};
template<typename T> struct T2 { static constexpr bool value = sizeof(T) == 2; };
static_assert(IsTypePredicate<T2>);
static_assert(!IsTypePredicate<T1>);
template<typename T, typename U, typename... Ts>
concept OneOf = (Same<T, Ts> || ...);
static_assert(OneOf<int, long, int>);
static_assert(!OneOf<long, int, char, char>);
namespace piecewise_substitution {
template <typename T>
concept True = true;
template <typename T>
concept A = True<T> || T::value;
template <typename T>
concept B = (True<T> || T::value);
template <typename T>
concept C = !True<T> && T::value || true;
template <typename T>
concept D = (!True<T> && T::value) || true;
template <typename T>
concept E = T::value || True<T>;
template <typename T>
concept F = (T::value || True<T>);
template <typename T>
concept G = T::value && !True<T> || true;
template <typename T>
concept H = (T::value && !True<T>) || true;
template <typename T>
concept I = T::value;
static_assert(A<int>);
static_assert(B<int>);
static_assert(C<int>);
static_assert(D<int>);
static_assert(E<int>);
static_assert(F<int>);
static_assert(G<int>);
static_assert(H<int>);
static_assert(!I<int>);
}
// Short ciruiting
template<typename T> struct T3 { using type = typename T::type; };
// expected-error@-1{{type 'char' cannot be used prior to '::' because it has no members}}
// expected-error@-2{{type 'short' cannot be used prior to '::' because it has no members}}
template<typename T>
concept C6 = sizeof(T) == 1 && sizeof(typename T3<T>::type) == 1;
// expected-note@-1{{while substituting template arguments into constraint expression here}}
// expected-note@-2{{in instantiation of template class 'T3<char>' requested here}}
template<typename T>
concept C7 = sizeof(T) == 1 || sizeof(
// expected-note@-1{{while substituting template arguments into constraint expression here}}
typename
T3<T>
// expected-note@-1{{in instantiation of template class 'T3<short>' requested here}}
::type) == 1;
static_assert(!C6<short>);
static_assert(!C6<char>); // expected-note{{while checking the satisfaction of concept 'C6<char>' requested here}}
static_assert(C7<char>);
static_assert(!C7<short>); // expected-note{{while checking the satisfaction of concept 'C7<short>' requested here}}
// Make sure argument list is converted when instantiating a CSE.
template<typename T, typename U = int>
concept SameSize = sizeof(T) == sizeof(U);
template<typename T>
struct X { static constexpr bool a = SameSize<T>; };
static_assert(X<unsigned>::a);
// static_assert concept diagnostics
template<typename T>
concept Large = sizeof(T) > 100;
// expected-note@-1 2{{because 'sizeof(small) > 100' (1 > 100) evaluated to false}}
struct small { };
static_assert(Large<small>);
// expected-error@-1 {{static_assert failed}}
// expected-note@-2 {{because 'small' does not satisfy 'Large'}}
static_assert(Large<small>, "small isn't large");
// expected-error@-1 {{static_assert failed "small isn't large"}}
// expected-note@-2 {{because 'small' does not satisfy 'Large'}}
// Make sure access-checking can fail a concept specialization
class T4 { static constexpr bool f = true; };
template<typename T> concept AccessPrivate = T{}.f;
// expected-note@-1{{because substituted constraint expression is ill-formed: 'f' is a private member of 'T4'}}
static_assert(AccessPrivate<T4>);
// expected-error@-1{{static_assert failed}}
// expected-note@-2{{because 'T4' does not satisfy 'AccessPrivate'}}
template<typename T, typename U>
// expected-note@-1{{template parameter is declared here}}
concept C8 = sizeof(T) > sizeof(U);
template<typename... T>
constexpr bool B8 = C8<T...>;
// expected-error@-1{{pack expansion used as argument for non-pack parameter of concept}}
// Make sure we correctly check for containsUnexpandedParameterPack
template<typename T>
concept C9 = true;
template <typename Fn, typename... Args>
using invoke = typename Fn::template invoke<Args...>;
template <typename C, typename... L>
// The converted argument here will not containsUnexpandedParameterPack, but the
// as-written one will.
requires (C9<invoke<C, L>> &&...)
struct S { };