Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Disagreement Between clang and gcc on "Deducing this" Behavior

I was playing around with the new "deducing this" functionality in C++23, and found a case that gcc and clang disagree on, and I was hoping to get a ruling on which compiler is correct. I've minimized the original code I was working on into the following example. Consider the following case:

#include <utility>
#include <type_traits>

struct foo {
    int asdf;

    template <class T, class O>
    using conversion_type = std::conditional_t<
        std::is_lvalue_reference_v<O>,
        T&,
        T
    >;

    template <class Self>
    operator conversion_type<int, Self>(this Self&& self) {
        return std::forward<Self>(self).asdf;
    }
};

int main() {
    foo f;
    int& fdsa = f;
    int&& asdf = std::move(f);
}

Without worrying too much about why on Earth I was doing this, I was trying to declare an implicit conversion operator that changes the value category of the type it converts TO based on the deduced value category of the object being converted FROM.

In this particular case, if the object to be converted is an lvalue, I'd like the conversion operator to resolve to converting to an lvalue reference to the subobject, and if not, I'd like it to resolve to converting to a temporary (not an rvalue reference, I'd like it to instead move the subobject into a new temporary).

gcc is entirely willing to compile this code, and it appears to work as I was expecting. clang will compile the third line inside of main, but will not compile the second, claiming that non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'foo', which sounds to me like it's not even considering the conversion operator.

Given the fact that clang appears to be inconsistent in its handling of this, I assume this is likely a clang bug, but I wanted to see what the general wisdom was.

Here's a link to compiler explorer that demonstrates the issue: https://godbolt.org/z/dG6jTj9rr

If you switch the compiler to any version of gcc 14, it will build without issues. Any ideas?

like image 232
Chris Fretz Avatar asked Sep 02 '25 03:09

Chris Fretz


1 Answers

The program is well-formed and clang and msvc are wrong to give a diagnostic for int& fdsa = f; .

In particular, you're using a forwarding reference which means when you wrote int &fdsa = f;, the parameter Self will be deduced as foo& which is an non-const lvalue reference. This in turn means that conversion_type<int, Self> will be int&.

And a call to a function returning an lvalue refernce is considered to be an lvalue and we're allowed to bind the result to an non-const lvalue ref fdsa.

Here is the confirmed clang bug:

Clang rejects valid program involving conversion function with lvalue ref return type

like image 188
Anoop Rana Avatar answered Sep 04 '25 18:09

Anoop Rana