[Bug c++/90734] New: [concepts] Pre-normalization substitution into constraints of templated function breaks subsumption
Casey at Carter dot net
gcc-bugzilla@gcc.gnu.org
Mon Jun 3 17:05:00 GMT 2019
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90734
Bug ID: 90734
Summary: [concepts] Pre-normalization substitution into
constraints of templated function breaks subsumption
Product: gcc
Version: 10.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: Casey at Carter dot net
Target Milestone: ---
Created attachment 46447
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=46447&action=edit
Repro
Compiling this program:
template <bool B>
inline constexpr bool bool_ = B;
#if defined(WORKAROUND)
template<class T, class U>
concept bool Same_impl = __is_same_as(T, U);
#else
template <class T, class U>
concept bool Same_impl = bool_<__is_same_as(T, U)>;
#endif
template<class T, class U>
concept bool Same = Same_impl<T, U> && Same_impl<U, T>;
template<class T>
concept bool Foo = Same<const T&, const T&>;
template<class T>
concept bool Bar = Foo<T> && Same<T, T>;
template<class T>
struct S1 {
// overload set incorrectly is ambiguous (should resolve to second
overload)
static constexpr bool f() requires Foo<T> { return false; }
static constexpr bool f() requires Bar<T> { return true; }
};
template<class T>
struct S2 {
// overload set incorrectly is not ambiguous (resolves to third
overload)
static constexpr bool f() requires Foo<T> { return false; }
static constexpr bool f() requires Bar<T> { return false; }
static constexpr bool f() requires bool_<true> && true { return true; }
};
template<class T>
concept bool can_f = requires { T::f(); };
int main() {
static_assert(Foo<int>);
static_assert(Bar<int>);
static_assert(can_f<S1<int>>); // Fails
static_assert(S1<int>::f()); // Bogus error
static_assert(!can_f<S2<int>>); // Fails
#ifndef WORKAROUND
static_assert(S2<int>::f()); // Bogus non-error
#endif
}
with "-std=c++2a -fconcepts" produces diagnostics:
/home/casey/casey/Desktop/repro.cpp: In function ‘int main()’:
/home/casey/casey/Desktop/repro.cpp:43:19: error: static assertion failed
43 | static_assert(can_f<S1<int>>); // Fails
| ^~~~~~~~~~~~~~
/home/casey/casey/Desktop/repro.cpp:44:30: error: call of overloaded ‘f()’
is ambiguous
44 | static_assert(S1<int>::f()); // Bogus error
| ^
/home/casey/casey/Desktop/repro.cpp:24:27: note: candidate: ‘static
constexpr bool S1<T>::f() requires Foo<T> [with T = int]’
24 | static constexpr bool f() requires Foo<T> { return false; }
| ^
/home/casey/casey/Desktop/repro.cpp:25:27: note: candidate: ‘static
constexpr bool S1<T>::f() requires Bar<T> [with T = int]’
25 | static constexpr bool f() requires Bar<T> { return true; }
| ^
/home/casey/casey/Desktop/repro.cpp:46:19: error: static assertion failed
46 | static_assert(!can_f<S2<int>>); // Fails
| ^~~~~~~~~~~~~~~
when it should diagnose only the static_assert on line 48. Bar<T> subsumes
Foo<T>, so S1<int>::f should be unambiguous. Conversely, Neither Bar<T> nor
bool_<true> && true subsumes the other, so S2<int>::f should be ambiguous. The
compiler's disagreement with both of these facts suggests premature
substitution replacing bool_<__is_same_as(T, T)> and bool_<__is_same_as(const
T&, const T&)> with bool_<true> *before* determination of subsumption in
overload resolution. That replacement would result in Foo<T> being replaced
with bool_<true> && bool_<true>, and Bar<T> being replaced with bool_<true> &&
bool_<true> && bool_<true> && bool_<true> which *would* produce the observed
behavior during overload resolution.
More information about the Gcc-bugs
mailing list