https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115939
Bug ID: 115939 Summary: Cannot unambiguously compare iterators in std::unordered_map with mapped type std::expected<std::any, Y>> Product: gcc Version: 14.1.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: halfflat at gmail dot com Target Milestone: --- Created attachment 58667 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=58667&action=edit Preprocessed .ii file from example code Consider the following code: #include <any> #include <expected> #include <unordered_map> struct Y {}; std::unordered_map<int, std::expected<std::any, Y>> m; bool r = m.begin()==m.end(); When compiled with g++ -c -std=c++23 -pedantic we get an "ambiguous overload for ‘operator==’" error. This issue has been replicated on Compiler Explorer (https://godbolt.org/z/cqoedqKbr). It is not clear to me if this results from a fundamental issue in the standard library specification or is a consequence of the implementation in libstdc++. The original context of the bug was in code that was attempting to use a std::unordered_map<std::type_index, std::function<std::expected<std::any, failure> (std::string_view)>> (where failure was a separately defined type). Compiler output below: % g++ -v -save-temps -c -std=c++23 -pedantic bug.cc Using built-in specs. COLLECT_GCC=g++ Target: x86_64-pc-linux-gnu Configured with: /build/gcc/src/gcc/configure --enable-languages=ada,c,c++,d,fortran,go,lto,m2,objc,obj-c++,rust --enable-bootstrap --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://gitea.artixlinux.org/packages/gcc/issues --with-build-config=bootstrap-lto --with-linker-hash-style=gnu --with-system-zlib --enable-__cxa_atexit --enable-cet=auto --enable-checking=release --enable-clocale=gnu --enable-default-pie --enable-default-ssp --enable-gnu-indirect-function --enable-gnu-unique-object --enable-libstdcxx-backtrace --enable-link-serialization=1 --enable-linker-build-id --enable-lto --enable-multilib --enable-plugin --enable-shared --enable-threads=posix --disable-libssp --disable-libstdcxx-pch --disable-werror Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 14.1.1 20240507 (GCC) COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-std=c++23' '-Wpedantic' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/cc1plus -E -quiet -v -D_GNU_SOURCE bug.cc -mtune=generic -march=x86-64 -std=c++23 -Wpedantic -fpch-preprocess -o bug.ii ignoring nonexistent directory "/usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/../../../../x86_64-pc-linux-gnu/include" ignoring nonexistent directory "/home/sam/pkg/include" #include "..." search starts here: #include <...> search starts here: /usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/../../../../include/c++/14.1.1 /usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/../../../../include/c++/14.1.1/x86_64-pc-linux-gnu /usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/../../../../include/c++/14.1.1/backward /usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include /usr/local/include /usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/include-fixed /usr/include End of search list. COLLECT_GCC_OPTIONS='-v' '-save-temps' '-c' '-std=c++23' '-Wpedantic' '-shared-libgcc' '-mtune=generic' '-march=x86-64' /usr/lib/gcc/x86_64-pc-linux-gnu/14.1.1/cc1plus -fpreprocessed bug.ii -quiet -dumpbase bug.cc -dumpbase-ext .cc -mtune=generic -march=x86-64 -Wpedantic -std=c++23 -version -o bug.s GNU C++23 (GCC) version 14.1.1 20240507 (x86_64-pc-linux-gnu) compiled by GNU C version 14.1.1 20240507, GMP version 6.3.0, MPFR version 4.2.1, MPC version 1.3.1, isl version isl-0.26-GMP GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072 Compiler executable checksum: 79593118236b8aa0b562fa91bdea97d6 bug.cc:7:19: error: ambiguous overload for ‘operator==’ (operand types are ‘std::unordered_map<int, std::expected<std::any, Y> >::iterator’ {aka ‘std::__detail::_Insert_base<int, std::pair<const int, std::expected<std::any, Y> >, std::allocator<std::pair<const int, std::expected<std::any, Y> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::iterator’} and ‘std::unordered_map<int, std::expected<std::any, Y> >::iterator’ {aka ‘std::__detail::_Insert_base<int, std::pair<const int, std::expected<std::any, Y> >, std::allocator<std::pair<const int, std::expected<std::any, Y> > >, std::__detail::_Select1st, std::equal_to<int>, std::hash<int>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, std::__detail::_Hashtable_traits<false, false, true> >::iterator’}) 7 | bool r = m.begin()==m.end(); | ~~~~~~~~~^~~~~~~~~ | | | | | _Node_iterator<[...],[...],[...]> | _Node_iterator<[...],[...],[...]> In file included from bug.cc:2: /usr/include/c++/14.1.1/expected:1133:9: note: candidate: ‘constexpr bool std::operator==(const expected<_Tp, _Er>&, const _Up&) [with _Up = __detail::_Node_iterator<pair<const int, expected<any, Y> >, false, false>; _Tp = any; _Er = Y]’ (reversed) 1133 | operator==(const expected& __x, const _Up& __v) | ^~~~~~~~ In file included from /usr/include/c++/14.1.1/bits/hashtable.h:35, from /usr/include/c++/14.1.1/bits/unordered_map.h:33, from /usr/include/c++/14.1.1/unordered_map:41, from bug.cc:3: /usr/include/c++/14.1.1/bits/hashtable_policy.h:407:7: note: candidate: ‘bool std::__detail::operator==(const _Node_iterator_base<std::pair<const int, std::expected<std::any, Y> >, false>&, const _Node_iterator_base<std::pair<const int, std::expected<std::any, Y> >, false>&)’ 407 | operator==(const _Node_iterator_base& __x, const _Node_iterator_base& __y) | ^~~~~~~~