On 17/04/15 01:03 +0200, Daniel Krügler wrote:
2015-04-16 14:33 GMT+02:00 Jonathan Wakely <jwakely....@gmail.com>:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65760

I don't understand why commenting out *any one* of the lines marked
(1), (2), (3), (4) causes this to compile:

#include <functional>

struct C {
    C() = default;

    C(std::function<C(int)>);  // (1)
    C(std::function<C(int, int)>); // (2)
    template <class T> C operator () (T&&); // (3)
    template <class T> C operator () (T&&, T&&); // (4)
};

My current understanding of the state of affairs is still complete in
some details, but let me still throw in my 2 cents: The compiler sees
an object of C constructed by an rvalue of C. Now we have - in
addition to the copy/move constructors - two corresponding pairs of
function call operator and converting constructor to consider. Let me
simplify the situation a bit more by removing the additional layer of
template deduction of the call operators to:

struct C
{
 C() = default;

 C(std::function<C(int)>);  // (1)
 C(std::function<C(int, int)>); // (2)
 C operator()(int); // (3)
 C operator()(int, int); // (4)
};

In the presence of all four members the compiler is allowed (I think
by [temp.inst] p7) to instantiate one or both of the different
std::function specializations, because it has to respect possible
conversions. When this happens, the converting template constructor
declaration of std::function also needs to be instantiated. While
doing this, we come to the point where within the SFINAE condition
std::is_convertible<C, C> needs to be instantiated, effectively
leading to a situation that we have two different contexts, in which
the compiler needs to evaluate the result the self-conversion of C, C
never becoming completed to realize that during that attempt.

If *any* of the four members is missing, we don't have the situation
that two conversion sequences based on function template deduction
need to be partially ordered, we have only the non-template copy/move
constructor against exactly one possible function template. For this
to order, the compiler doesn't require instantiation of the converting
constructor of std::function.

[...]

Nonetheless, my understanding of your fix is that it actually is not
conforming to what the standard currently requires (This seems to
match you own thinking expressed above), because [func.wrap.func.con]
p8 requires:

"shall not participate in overload resolution unless f is Callable
(20.9.12.2) for argument types ArgTypes... and return type R."

and if we unroll this against the definition Callable (ending in
[func.require] p2) we finally end up in a required test whether the
return type of the invokable thingee has a value of
std::is_convertible<C, C>::value == true (C has the role of the return
type R). This is so, *even*, if LWG issue

http://cplusplus.github.io/LWG/lwg-active.html#2420

would be fixed as described, because we have no void return type involved here.

My current position is that we presumably have a Standard Library
issue lurking around, because I see no way how any library can
implement std::function without breaking this seemingly valid example
case. Either the Standard Library needs to express stronger
constraints on the return type R of std::function<R(ArgTypes...)> (so
to make the example invalid), or - what I would currently prefer - the
library would need to reduce the SFINAE constraints of the
std::function template constructor basically ending in not requiring
that R is complete, or in other words: not requiring the final part of
the Callable test involving the implicit conversion of the functor
result to the described result type R of
std::function<R(ArgTypes...)>.

To follow the intention of std::functions design, the Library could
require that when the constructor definition of

template<class F> function(F);

becomes instantiated, the current SFINAE requirements are to be
tested, possibly making this definition instantiation ill-formed.

Summarizing this, I consider your suggested resolution as useful for
practical reasons.

While I agree with Daniel that my suggested fix may not be strictly
conforming, I think it is worth doing anyway, so I'm committing it.

Tested powerpc64le-linux, committed to trunk.


commit bc3d6d30fd620ea1d7d286512f983a7a1ddb99c0
Author: Jonathan Wakely <jwak...@redhat.com>
Date:   Fri Apr 17 13:25:42 2015 +0100

    	PR libstdc++/65760
    	* include/std/functional (__check_func_return_type): Use is_same to
    	avoid using _is_convertible on incomplete types.
    	* testsuite/20_util/function/65760.cc: New.

diff --git a/libstdc++-v3/include/std/functional b/libstdc++-v3/include/std/functional
index e9d48e4..946cf63 100644
--- a/libstdc++-v3/include/std/functional
+++ b/libstdc++-v3/include/std/functional
@@ -1962,7 +1962,7 @@ _GLIBCXX_MEM_FN_TRAITS(&&, false_type, true_type)
 
   template<typename _From, typename _To>
     using __check_func_return_type
-      = __or_<is_void<_To>, is_convertible<_From, _To>>;
+      = __or_<is_void<_To>, is_same<_From, _To>, is_convertible<_From, _To>>;
 
   /**
    *  @brief Primary class template for std::function.
diff --git a/libstdc++-v3/testsuite/20_util/function/65760.cc b/libstdc++-v3/testsuite/20_util/function/65760.cc
new file mode 100644
index 0000000..e3858b4
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/function/65760.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 2015 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+// { dg-do compile }
+
+// libstdc++/65760
+// c.f. https://gcc.gnu.org/ml/libstdc++/2015-04/msg00116.html
+
+#include <functional>
+
+struct C {
+    C() = default;
+
+    C(std::function<C(int)>);
+    C(std::function<C(int, int)>);
+    C operator()(int);
+    C operator()(int, int);
+};
+
+int main() {
+    C c = C();
+}
+

Reply via email to