Fedora Account System
Red Hat Associate
Red Hat Customer
Created attachment 1391759 [details] C++ source file showing failure to resolve overload Description of problem: The openfst package is failing to build in Rawhide. I have distilled the problem down to the attached file. With GCC 7, compiling that file with "g++ -c overload.cpp" succeeds. With GCC 8 in Rawhide, this output is produced: overload.cpp: In static member function 'static void fst::AddOnImpl<FST, T>::Read(std::istream&)': overload.cpp:30:33: error: call of overloaded 'ReadType(std::istream&, int32_t*)' is ambiguous ReadType(strm, &magic_number); ^ overload.cpp:7:22: note: candidate: 'std::istream& fst::ReadType(std::istream&, T*) [with T = int; typename std::enable_if<std::is_class<_Tp>::value, T>::type* <anonymous> = ((typename std::enable_if<std::is_class<int>::value, int>::type*)nullptr)]' inline std::istream &ReadType(std::istream &strm, T *t) { ^~~~~~~~ overload.cpp:13:22: note: candidate: 'std::istream& fst::ReadType(std::istream&, T*) [with T = int; typename std::enable_if<std::is_arithmetic<_Tp>::value, T>::type* <anonymous> = ((typename std::enable_if<std::is_arithmetic<int>::value, int>::type*)nullptr)]' inline std::istream &ReadType(std::istream &strm, T *t) { ^~~~~~~~ Simply removing the parent class declaration from AddOnImpl makes the compile succeed with GCC 8. Version-Release number of selected component (if applicable): gcc-8.0.1-0.9.fc28.x86_64 How reproducible: Always Steps to Reproduce: 1. Download the attached C++ source file 2. Run "g++ -c overload.cpp" Actual results: The error shown above. Expected results: Successful build. Additional info:
This changed with http://gcc.gnu.org/r256866 .
Clang accepts it even if we instantiate that function, by adding: struct X { using Arc = int; }; int main() { fst::AddOnImpl<X, void> a; a.Read(std::cin); } But all compilers reject this reduced example as ambiguous: namespace std { struct istream { }; struct true_type { static constexpr bool value = true; }; struct false_type { static constexpr bool value = false; }; template<bool, typename T = void> struct enable_if { using type = T; }; template<> struct enable_if<false> { }; template<typename> struct is_class : false_type { }; template<typename> struct is_arithmetic : false_type { }; template<> struct is_arithmetic<int> : true_type { }; } // std template <class T, typename std::enable_if<std::is_class<T>::value, T>::type* = nullptr> inline std::istream& ReadType(std::istream &strm, T *) { return strm; } template <class T, typename std::enable_if<std::is_arithmetic<T>::value, T>::type* = nullptr> inline std::istream& ReadType(std::istream &strm, T *) { return strm; } void Read(std::istream &strm) { int magic_number = 0; ReadType(strm, &magic_number); } So I'm not sure what the right behaviour is. The code can be easily made to compile by using enable_if on the return types instead of as default template arguments: template <class T> inline typename std::enable_if<std::is_class<T>::value, std::istream&>::type ReadType(std::istream &strm, T *) { ... } This definitely isn't ambiguous, as the other overload gets a substitution failure sooner.
CCing Jason.
If the new G++ behaviour is correct then we need to fix libstdc++: https://gcc.gnu.org/ml/gcc-help/2018-02/msg00065.html
Oops, comment 2 was a bad reduction, the enable_if<false> specialization was wrong. This is a correct reduction which fails with GCC trunk and passes with other compilers: struct istream { }; struct true_type { static constexpr bool value = true; }; struct false_type { static constexpr bool value = false; }; template<bool, typename T = void> struct enable_if { using type = T; }; template<typename T> struct enable_if<false, T> { }; template<typename> struct is_class : false_type { }; template<typename> struct is_arithmetic : false_type { }; template<> struct is_arithmetic<int> : true_type { }; template <class T, typename enable_if<is_class<T>::value, T>::type* = nullptr> inline istream& ReadType(istream &strm, T *) { return strm; } template <class T, typename enable_if<is_arithmetic<T>::value, T>::type* = nullptr> inline istream& ReadType(istream &strm, T *) { return strm; } void Read(istream &strm) { int magic_number = 0; ReadType(strm, &magic_number); }
Bah still not right, I tested the wrong file, please ignore that one too!
The upstream bug now has a minimal reproducer.
This has now been fixed upstream, so should get fixed next time GCC is updated in rawhide.
Fixed in gcc-8.0.1-0.13.fc28