https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94888

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|WAITING                     |RESOLVED
         Resolution|---                         |INVALID

--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Reduced:

//RemoveRef
template<typename _Tp>
struct RemoveRef
{ typedef _Tp   type; };

template<typename _Tp>
struct RemoveRef<_Tp&>
{ typedef _Tp   type; };

template<typename _Tp>
struct RemoveRef<_Tp&&>
{ typedef _Tp   type; };

//Forward
template<typename _Tp>
_Tp&&
Forward(typename RemoveRef<_Tp>::type& __t)
{ return static_cast<_Tp&&>(__t); }

template<typename _Tp>
_Tp&&
Forward(typename RemoveRef<_Tp>::type&& __t)
{ return static_cast<_Tp&&>(__t); }

template <typename T>
struct FunctionImpl
{
    template <typename Ty>
    FunctionImpl(Ty&& t_) : t(Forward<Ty>(t_)) {}

    T t;
};

struct FunctionBridger
{
    template <typename T>
    FunctionBridger(T&& func_)
    {
      delete new FunctionImpl<typename RemoveRef<T>::type>(Forward<T>(func_) );
    }
};

struct Function
        : public FunctionBridger
{
    template <typename Ty>
    Function( Ty&& func) : FunctionBridger(Forward<Ty>(func)) { }

    ~Function() {}
};

void f() { }

int main()
{
    Function func = &f;
}

The variable definition in main() uses copy-initialization, so it first creates
a temporary of type Function, then it copies it. The copy uses the
Function(Ty&&) constructor recursively, until it overflows the stack.

Clang behaves the same if you use -fno-elide-constructors

Your code is invalid, because it assumes that copy elision happens, which is
not guaranteed in C++14. For C++17 it works correctly.

I'm not sure *why* G++ doesn't elide the copy, as it usually does do that even
in C++14. But it's not required to do so before C++17, so this isn't a bug.

If you remove the ~Function() destructor then G++ does elide the copy.

You could also constrain the Function(Ty&&) constructor so it will not be used
to copy/move an object of the same type.

Reply via email to