Closed
Description
Title: Lowered UFCS doesn't SFINAE.
Description:
Suppose #496 was fixed.
Attempting to check whether a UFCS candidate expression is well-formed
results in a hard error inside the UFCS machinery.
Minimal reproducer (https://cpp2.godbolt.org/z/Pn46vKMej):
#include "cpp2util.h"
template<typename T> [[nodiscard]] auto f()
requires (CPP2_UFCS_0_NONLOCAL(a, T()))
{
}
struct B { };
static_assert([]<class T>() {
return !requires { f<T>(); };
}.template operator()<B>());
Commands:
cppfront -clean-cpp1 main.cpp2
clang++17 -std=c++23 -stdlib=libc++ -lc++abi -pedantic-errors -Wall -Wextra -Wconversion -I . main.cpp
Expected result:
The assertion to pass.
Actual result and error:
Output:
build/_cppfront/main.cpp:3:32: error: use of undeclared identifier 'a'
3 | requires (CPP2_UFCS_0_NONLOCAL(a, T()))
| ^
build/_cppfront/main.cpp:3:11: note: in instantiation of function template specialization 'f()::(anonymous class)::operator()<B>' requested here
3 | requires (CPP2_UFCS_0_NONLOCAL(a, T()))
| ^
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:746:47: note: expanded from macro 'CPP2_UFCS_0_NONLOCAL'
746 | #define CPP2_UFCS_0_NONLOCAL(FUNCNAME,PARAM1) \
| ^
build/_cppfront/main.cpp:3:11: note: while substituting template arguments into constraint expression here
3 | requires (CPP2_UFCS_0_NONLOCAL(a, T()))
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:746:47: note: expanded from macro 'CPP2_UFCS_0_NONLOCAL'
746 | #define CPP2_UFCS_0_NONLOCAL(FUNCNAME,PARAM1) \
| ^
747 | [](auto&& obj) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
748 | if constexpr (requires{ CPP2_FORWARD(obj).FUNCNAME(); }) { \
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
749 | return CPP2_FORWARD(obj).FUNCNAME(); \
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
750 | } else { \
| ~~~~~~~~~~
751 | return FUNCNAME(CPP2_FORWARD(obj)); \
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
752 | } \
| ~~~
753 | }(PARAM1)
| ~~~~~~~~~
build/_cppfront/main.cpp:8:22: note: while checking constraint satisfaction for template 'f<B>' required here
8 | return !requires { f<T>(); };
| ^
build/_cppfront/main.cpp:8:22: note: in instantiation of function template specialization 'f<B>' requested here
build/_cppfront/main.cpp:8:22: note: in instantiation of requirement here
8 | return !requires { f<T>(); };
| ^~~~~~
build/_cppfront/main.cpp:9:12: note: in instantiation of function template specialization '(anonymous class)::operator()<B>' requested here
9 | }.template operator()<B>());
| ^
build/_cppfront/main.cpp:3:32: error: no matching function for call to 'a'
3 | requires (CPP2_UFCS_0_NONLOCAL(a, T()))
| ^
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:751:16: note: expanded from macro 'CPP2_UFCS_0_NONLOCAL'
751 | return FUNCNAME(CPP2_FORWARD(obj)); \
| ^~~~~~~~
build/_cppfront/main.cpp:3:11: note: in instantiation of function template specialization 'f()::(anonymous class)::operator()<B>' requested here
3 | requires (CPP2_UFCS_0_NONLOCAL(a, T()))
| ^
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:746:47: note: expanded from macro 'CPP2_UFCS_0_NONLOCAL'
746 | #define CPP2_UFCS_0_NONLOCAL(FUNCNAME,PARAM1) \
| ^
build/_cppfront/main.cpp:3:11: note: while substituting template arguments into constraint expression here
3 | requires (CPP2_UFCS_0_NONLOCAL(a, T()))
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
raw.githubusercontent.com/hsutter/cppfront/main/include/cpp2util.h:746:47: note: expanded from macro 'CPP2_UFCS_0_NONLOCAL'
746 | #define CPP2_UFCS_0_NONLOCAL(FUNCNAME,PARAM1) \
| ^
747 | [](auto&& obj) CPP2_FORCE_INLINE_LAMBDA -> decltype(auto) { \
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
748 | if constexpr (requires{ CPP2_FORWARD(obj).FUNCNAME(); }) { \
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
749 | return CPP2_FORWARD(obj).FUNCNAME(); \
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
750 | } else { \
| ~~~~~~~~~~
751 | return FUNCNAME(CPP2_FORWARD(obj)); \
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
752 | } \
| ~~~
753 | }(PARAM1)
| ~~~~~~~~~
build/_cppfront/main.cpp:8:22: note: while checking constraint satisfaction for template 'f<B>' required here
8 | return !requires { f<T>(); };
| ^
build/_cppfront/main.cpp:8:22: note: while substituting deduced template arguments into function template 'f' [with T = B]
build/_cppfront/main.cpp:8:22: note: in instantiation of requirement here
8 | return !requires { f<T>(); };
| ^~~~~~
build/_cppfront/main.cpp:9:12: note: in instantiation of function template specialization '(anonymous class)::operator()<B>' requested here
9 | }.template operator()<B>());
| ^
2 errors generated.