Discussion:
A weird bug in Clang
(too old to reply)
Andrey Tarasevich
2024-09-20 02:59:23 UTC
Permalink
Seems to be reproducible in all Clang versions

struct A {};

template <typename = int> struct C
{
C() = default;
C(const A &) {}
C &operator =(const A &a) { return operator =(C(a)); }
};

int main()
{
A a;
C<> c;
c = a;
}

Results in

error: no viable conversion from 'C<>' to 'const A'
7 | C &operator =(const A &a) { return operator =(C(a)); }
| ^~~~

It appears that a user-declared converting assignment operator somehow
suppressed the compiler-provided copy-assignment operator for `C<>`. The
issue is only present when `C` is a template.

The problem can be fixed by calling the compiler-provided
copy-assignment operator through an explicit `this->`

C &operator =(const A &a) { return this->operator =(C(a)); }

or by adding an explicit declaration of the copy-assignment operator

C &operator =(const C &) = default;

Am I missing something obvious here? GCC and MSVC++ accept the original
version of the code without any issues.
--
Best regards,
Andrey
Andrey Tarasevich
2024-09-20 14:12:39 UTC
Permalink
  struct A {};
  template <typename = int> struct C
  {
    C() = default;
    C(const A &) {}
    C &operator =(const A &a) { return operator =(C(a)); }
  };
  int main()
  {
    A a;
    C<> c;
    c = a;
  }
This significantly reduced version of the code sheds some light on the
inner workings of the bug

template <typename = int> struct C
{
C &foo(const C &c) { return operator =(c); }
};

int main()
{
C<> c;
c.foo(c);
}

Clang complains with

error: explicit qualification required to use member 'operator=' from
dependent base class
3 | C &foo(const C &c) { return operator =(c); }

"Dependent base class"? What "dependent base class"? There are no base
classes involved in this example.

Apparently Clang decides that a reference to an implicitly-declared
copy-assignment operator is an accidental reference to an operator from
a base class (since it does not see an explicit declaration here). This
also explains why `this->` provides a workaround.
--
Best regards,
Andrey
Loading...