The below example is ill-formed - the requires clause should not be satisfied due to the failure to instantiate W1<int>, but GCC accepts the code nonetheless. Clang rejects the code. $ cat gcc-bug.cpp template<class> concept C1 = true; template<class T> using W1 = decltype(nonexistent<T>(0)); template<class T> requires C1<W1<T>> void func(T); void test() { func(0); } $ g++ -c -std=c++20 gcc-bug.cpp $ clang++ -c -std=c++20 gcc-bug.cpp gcc-bug.cpp:10:3: error: no matching function for call to 'func' 10 | func(0); | ^~~~ gcc-bug.cpp:7:6: note: candidate template ignored: constraints not satisfied [with T = int] 7 | void func(T); | ^ gcc-bug.cpp:3:39: note: because substituted constraint expression is ill-formed: use of undeclared identifier 'nonexistent' 3 | template<class T> using W1 = decltype(nonexistent<T>(0)); | ^ 1 error generated.
Thanks for the bug report, I think this is pretty much a dup of PR102419. GCC is behaving correctly here: the normal form of the constraint C1<W1<T>> is just 'true (with empty parameter mapping)' which is independent of the template parameter, so the constraint is trivially satisfied for any choice of T. To get the behavior you desire, define C1 in a way that depends on its template parameter e.g. template<class T> concept C1 = requires { typename T; }; *** This bug has been marked as a duplicate of bug 102419 ***