llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.49k stars 11.78k forks source link

Member funciton overload resolution bug #96469

Open mix74rus opened 3 months ago

mix74rus commented 3 months ago

I'm not entirely sure, but to me it looks like this code shouldn't compile

#include <type_traits>

template<bool Overload>
struct Test {
    int Foo(int) requires Overload;
    double Foo(double) ;
};

int main() {
    static_assert(
        std::is_same_v<
            decltype(&Test<true>::Foo), 
            int(Test<true>::*)(int)
        >
    );
    return 0;
}

Test<true>::Foo looks ambiguous to me, and GCC and MSVC seem to agree, but not clang - https://godbolt.org/z/v35vez93z

While trying to understand this, I found that cppreference mentions following rule on "Address of an overloaded function" page:

For any pair of non-template functions where one is more constrained than another, the less constrained function is dropped from the set(since C++20)

I see how int overload might look "more constrained", but as I said, I'm not entirely sure

llvmbot commented 3 months ago

@llvm/issue-subscribers-clang-frontend

Author: Mikhail Lavrinovich (mix74rus)

I'm not entirely sure, but to me it looks like this code shouldn't compile ```c++ #include <type_traits> template<bool Overload> struct Test { int Foo(int) requires Overload; double Foo(double) ; }; int main() { static_assert( std::is_same_v< decltype(&Test<true>::Foo), int(Test<true>::*)(int) > ); return 0; } ``` `Test<true>::Foo` looks ambiguous to me, and GCC and MSVC seem to agree, but not clang - https://godbolt.org/z/v35vez93z While trying to understand this, I found that cppreference mentions following rule on ["Address of an overloaded function"](https://en.cppreference.com/w/cpp/language/overloaded_address) page: > For any pair of non-template functions where one is [more constrained](https://en.cppreference.com/w/cpp/language/constraints) than another, the less constrained function is dropped from the set(since C++20) I see how `int` overload might look "more constrained", but as I said, I'm not entirely sure
zygoloid commented 3 months ago

For function templates, we don't compare constraints unless the declarations are otherwise the same. In this case, there doesn't seem to be such a rule. Instead, we land in [over.over]/5:

Any given non-template function F0 is eliminated if the set contains a second non-template function that is more constrained than F0 according to the partial ordering rules of [temp.constr.order].

... which just directly compares the constraints without considering whether the signatures match.

For function templates, the relevant rule is instead:

Any given function template specialization F1 is eliminated if the set contains a second function template specialization whose function template is more specialized than the function template of F1 according to the partial ordering rules of [temp.func.order].

... which only considers constraints if the signatures are sufficiently similar.

I'm not certain whether this is intentional, but as far as I can see, Clang is implementing the wording in the standard, and the other compilers don't seem to be.