Full name of submitter (unless configured in github; will be published with the issue): Hubert Tong
Reference (section label): temp.constr.normal
Link to reflector thread (if any): N/A
Issue description
Consider:
template <auto> constexpr bool B = true;
template <unsigned X0> concept C = B<X0>;
template <unsigned short X1> concept C2 = C<X1>;
template <unsigned X> void f() requires C<X>; // #1
template <unsigned X> int f() requires C2<X> && true; // #2
void g() {
return f<65536>(); // should probably call #1
}
void h() {
f<0>(); // ambiguous?
}
When forming the normalized constraints, it is unclear how the type of X1 in the definition of C2 affects the parameter mapping. https://wg21.link/temp.constr.normal#1.4 does not seem to address this at all.
There is implementation divergence:
GCC and MSVC reject the call to f from g (resolving to #2) and similarly resolves the call to f from h to #2.
Clang and EDG accept the call to f from g (resolving to #1) and rejects the call to f from h as ambiguous.
Online compiler link: https://godbolt.org/z/hEKaosbWe
Adopting the GCC/MSVC behaviour, which seems to ignore the type of X1 in the definition of C2, seems objectively wrong: 65536u is not a value that C2 accepts.
The Clang and EDG behaviour suggests that the parameter mapping for the B<X0> atomic constraints are different between #1 and #2. Presumably when substituting X from #2 into the normalized constraint for C2, some decoration was included.
Suggested resolution
Introducing some sort of "shadow constraint" that X is a valid template argument for a template parameter declared as unsigned short when normalizing the use of C2 from #2 would reject the call from g but accept the call from h as resolving to #2. This seems to be a sensible result, but leaves none of the surveyed implementations unscathed.
Full name of submitter (unless configured in github; will be published with the issue): Hubert Tong
Reference (section label): temp.constr.normal
Link to reflector thread (if any): N/A
Issue description
Consider:
When forming the normalized constraints, it is unclear how the type of
X1in the definition ofC2affects the parameter mapping. https://wg21.link/temp.constr.normal#1.4 does not seem to address this at all.There is implementation divergence:
GCC and MSVC reject the call to
ffromg(resolving to#2) and similarly resolves the call toffromhto#2.Clang and EDG accept the call to
ffromg(resolving to#1) and rejects the call toffromhas ambiguous.Online compiler link: https://godbolt.org/z/hEKaosbWe
Adopting the GCC/MSVC behaviour, which seems to ignore the type of
X1in the definition ofC2, seems objectively wrong:65536uis not a value thatC2accepts.The Clang and EDG behaviour suggests that the parameter mapping for the
B<X0>atomic constraints are different between#1and#2. Presumably when substitutingXfrom#2into the normalized constraint forC2, some decoration was included.Suggested resolution
Introducing some sort of "shadow constraint" that
Xis a valid template argument for a template parameter declared asunsigned shortwhen normalizing the use ofC2from#2would reject the call fromgbut accept the call fromhas resolving to#2. This seems to be a sensible result, but leaves none of the surveyed implementations unscathed.