microsoft / microsoft/STL

<concepts>: std::ranges::_Swap::_Use_ADL_swap -- error C2131: expression did not evaluate to a constant

Open
#4,363 7 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

compiler
Dominant language
C++
Stars
11.2k
Forks
1.7k
Avg merge
4d 15h
Merged PRs (30d)
22

Description

Describe the bug

Minimal reproduction: https://godbolt.org/z/66jcnWGq8

Code:

#include <map>
#include <ranges>

namespace some_namespace
{

template<typename LEFT_T, typename RIGHT_T>
void swap(LEFT_T && left, RIGHT_T && right)
        noexcept(noexcept(std::ranges::swap(std::forward<LEFT_T>(left), std::forward<RIGHT_T>(right))))
{
}

struct Inner
{
}; 

} // some_namespace

namespace different_namespace
{
template<typename TYPE_T>    
struct Outer { };

using SomeTemplate_t = Outer<some_namespace::Inner>;
using MapType_t = std::map < int, SomeTemplate_t >;
void function(void)
{
    MapType_t test = {{ 1, SomeTemplate_t()}, { 2, SomeTemplate_t()}, { 3, SomeTemplate_t()}};
    [[maybe_unused]] auto const testView = std::views::values(test);
}

} // namespace different_namespace

If you delete the noexcept specification of some_namespace::swap then the example compiles correctly on all three compilers.
https://godbolt.org/z/KTbjhTxdM

Alternatively, if you replace some_namespace::swap with using std::ranges::swap; then it compiles correctly on all three compilers. https://godbolt.org/z/d8cq4YTMe

It seems that somehow std::ranges::_Swap::_Use_ADL_swap is looking into the std::map value type, and instead of recognizing that there is no swap function in namespace different_namespace, it is instead looking into the namespace of the template parameter and seeing that there is a swap function in some_namespace.

Looking at the implementation of _Use_ADL_swap ( https://github.com/microsoft/STL/blob/1bc5ca60fcb41c2ed87a721d6ca2f77844cf6dc6/stl/inc/concepts#L117-L120 ) i don't see anything in the implementation that implies it's trying to look inside of the type's template parameters, just the type itself.

        concept _Use_ADL_swap = (_Has_class_or_enum_type<_Ty1> || _Has_class_or_enum_type<_Ty2>)
            && requires(_Ty1&& __t, _Ty2&& __u) {
                swap(static_cast<_Ty1&&>(__t), static_cast<_Ty2&&>(__u)); // intentional ADL
            };

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the minimal reproduction in the issue and inspect _Use_ADL_swap in stl/inc/concepts around lines 117–120. Compare the behavior with the linked Compiler Explorer examples and determine why the ranges swap check reaches the nested type's namespace; done means the reproduction compiles correctly without removing noexcept or replacing the user-defined swap.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.