https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102419
Patrick Palka <ppalka at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |ppalka at gcc dot gnu.org --- Comment #1 from Patrick Palka <ppalka at gcc dot gnu.org> --- The behavior of this testcase was changed with r11-7454 (the testcase concepts-return-req2.C added there is essentially identical to this one). Before this commit, we'd substitute template arguments into the return-type-requirement before checking satisfaction, and now we substitute template arguments as part of satisfaction (into the normal form of the constraint, which is just 'true (with an empty parameter mapping)'), which explains the behavior change. AFAICT, the standard is inconsistent about whether a separate substitution should be performed here. On the one hand, [expr.prim.req.compound] says - Substitution of template arguments (if any) into the return-type-requirement is performed. which suggests a separate substitution should be performed. On the other hand, the example in that same section says a compound-requirement is equivalent to a simple-requirement & nested-requirement: Given concepts C and D, requires { { E1 } -> C; { E2 } -> D<A1, ⋯, An>; }; is equivalent to requires { E1; requires C<decltype((E1))>; E2; requires D<decltype((E2)), A1, ⋯, An>; }; and we certainly shouldn't be doing a separate substitution when checking a nested-requirement. IIUC, GCC's behavior is consistent with the example. Generally GCC tries to avoid doing a separate substitution into a constraint whenever we can get away with it and instead perform the substitution as part of satisfaction. This e.g. also occurs for the type-constraint of a placeholder type: template<class, class> concept Y = true; template<class T> void f() { Y<typename T::type> auto y = 0; } template void f<int>(); // GCC accepts, Clang/MSVC reject