The difference between GCC 11 and GCC 10 / Clang seems to boil down to whether it accepts a templated constructor as a move constructor.
Here's the code example reduced further to illustrate this:
```
#include <utility> // for std::move
struct NonMovable {
NonMovable(NonMovable &&) = delete;
};
template <class T>
struct Maybe {
NonMovable mMember;
template <typename U>
Maybe(Maybe<U>&&);
};
void foo(Maybe<int>);
void unlucky(Maybe<int>&& x) {
foo(std::move(x));
}
```
Here, `NonMovable` has a deleted move constructor, so the default move constructor that the compiler would generate for `Maybe` is ill-formed. However, `Maybe` has a templated constructor which would be a match for the move if instantiated.
It looks like GCC 10 and Clang don't try to generated a move constructor for `Maybe`, they just use the templated one. GCC 11, however, ignores the templated constructor and tries to generate the default move constructor, which is then ill-formed.
The connection between the original testcase and this one is:
* `Maybe<nsTHashtable::EntryHandle>::Union` is not movable because it has a member of type `nsTHashtable::EntryHandle` which has a **non-trivial** move constructor.
* The attempt to move an object of type `Maybe<EntryHandle>` comes from the internals of `invoke_result`, which tries to check if the lambda (which has an `auto` parameter and therefore accepts its argument **by value**) is callable with an argument of type `Maybe<EntryHandle>&&`. The lambda's call operator is instantiated to have the signature `void (Maybe<EntryHandle> maybeEntryHandle)`, and then calling that with `Maybe<EntryHandle>&&` then requires calling the move constructor of `Maybe<EntryHandle>`.
I'm not sure yet which compiler is right. Will leave the needinfo on me until I can get some more info on that.
Bug 1710235 Comment 21 Edit History
Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.
The difference between GCC 11 and GCC 10 / Clang seems to boil down to whether it accepts a templated constructor as a move constructor.
Here's the code example reduced further to illustrate this:
```
#include <utility> // for std::move
struct NonMovable {
NonMovable(NonMovable &&) = delete;
};
template <class T>
struct Maybe {
NonMovable mMember;
template <typename U>
Maybe(Maybe<U>&&);
};
void foo(Maybe<int>);
void unlucky(Maybe<int>&& x) {
foo(std::move(x));
}
```
Here, `NonMovable` has a deleted move constructor, so the default move constructor that the compiler would generate for `Maybe` is ill-formed. However, `Maybe` has a templated constructor which would be a match for the move if instantiated.
It looks like GCC 10 and Clang don't try to generate a move constructor for `Maybe`, they just use the templated one. GCC 11, however, ignores the templated constructor and tries to generate the default move constructor, which is then ill-formed.
The connection between the original testcase and this one is:
* `Maybe<nsTHashtable::EntryHandle>::Union` is not movable because it has a member of type `nsTHashtable::EntryHandle` which has a **non-trivial** move constructor.
* The attempt to move an object of type `Maybe<EntryHandle>` comes from the internals of `invoke_result`, which tries to check if the lambda (which has an `auto` parameter and therefore accepts its argument **by value**) is callable with an argument of type `Maybe<EntryHandle>&&`. The lambda's call operator is instantiated to have the signature `void (Maybe<EntryHandle> maybeEntryHandle)`, and then calling that with `Maybe<EntryHandle>&&` then requires calling the move constructor of `Maybe<EntryHandle>`.
I'm not sure yet which compiler is right. Will leave the needinfo on me until I can get some more info on that.
The difference between GCC 11 and GCC 10 / Clang seems to boil down to whether it accepts a templated constructor as a move constructor.
Here's the code example reduced further to illustrate this:
```
#include <utility> // for std::move
struct NonMovable {
NonMovable(NonMovable &&) = delete;
};
template <class T>
struct Maybe {
NonMovable mMember;
template <typename U>
Maybe(Maybe<U>&&);
};
void foo(Maybe<int>);
void unlucky(Maybe<int>&& x) {
foo(std::move(x));
}
```
Here, `NonMovable` has a deleted move constructor, so the default move constructor that the compiler would generate for `Maybe` is ill-formed. However, `Maybe` has a templated constructor which would be a match for the move if instantiated.
It looks like GCC 10 and Clang don't try to generate a move constructor for `Maybe`, they just use the templated one. GCC 11, however, ignores the templated constructor and tries to generate the default move constructor, which is then ill-formed.
The connection between the original testcase and this one is:
* `Maybe<nsTHashtable::EntryHandle>::Union` is not movable because it has a member of type `nsTHashtable::EntryHandle` which has a **non-trivial** move constructor.
* The attempt to move an object of type `Maybe<EntryHandle>` comes from the internals of `invoke_result`, which tries to check if the lambda (which has an `auto` parameter and therefore accepts its argument **by value**) is callable with an argument of type `Maybe<EntryHandle>&&`. The lambda's call operator is instantiated to have the signature `void (Maybe<EntryHandle>)`, and then calling that with `Maybe<EntryHandle>&&` then requires calling the move constructor of `Maybe<EntryHandle>`.
I'm not sure yet which compiler is right. Will leave the needinfo on me until I can get some more info on that.