Fixes: https://github.com/llvm/llvm-project/issues/45563 ``` template<class T> concept True = true; template <class T> concept C1 = requires (T) { requires True<typename T::value> || True<T>; }; template <class T> constexpr bool foo() requires True<typename T::value> || True<T> { return true; } static_assert(C1<double>); // Previously failed due to SFINAE error static_assert(foo<int>()); // but this works fine. ``` The issue here is the discrepancy between how a [nested requirement is evaluated](https://github.com/llvm/llvm-project/blob/main/clang/lib/Sema/SemaTemplateInstantiate.cpp#L2331) Vs how a [non-nested requirement is evaluated](https://github.com/llvm/llvm-project/blob/main/clang/lib/Sema/SemaConcept.cpp#L167-L200). This patch makes constraint checking consistent for nested requirement and trailing requires expressions by reusing the same evaluator. Differential Revision: https://reviews.llvm.org/D138914
25 lines
756 B
C++
25 lines
756 B
C++
// RUN: %clang_cc1 -emit-pch -std=c++2a -o %t %s
|
|
// RUN: %clang_cc1 -std=c++2a -x ast -ast-print %t | FileCheck %s
|
|
|
|
// RUN: %clang_cc1 -emit-pch -std=c++2a -fpch-instantiate-templates -o %t %s
|
|
// RUN: %clang_cc1 -std=c++2a -x ast -ast-print %t | FileCheck %s
|
|
|
|
template<typename T>
|
|
concept C = true;
|
|
|
|
template<typename T, typename U>
|
|
concept C2 = true;
|
|
|
|
template<typename T>
|
|
bool f() {
|
|
// CHECK: requires (T t) { t++; { t++ } noexcept -> C; { t++ } -> C2<int>; typename T::a; requires T::val; requires C<typename T::val> || (C<typename T::val> || C<T>); };
|
|
return requires (T t) {
|
|
t++;
|
|
{ t++ } noexcept -> C;
|
|
{ t++ } -> C2<int>;
|
|
typename T::a;
|
|
requires T::val;
|
|
requires C<typename T::val> || (C<typename T::val> || C<T>);
|
|
};
|
|
}
|