diff mbox

Help needed debugging std::is_convertible problem (PR 65760)

Message ID 20150429160745.GN3618@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely April 29, 2015, 4:07 p.m. UTC
On 17/04/15 01:03 +0200, Daniel Krügler wrote:
>2015-04-16 14:33 GMT+02:00 Jonathan Wakely <jwakely.gcc@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.
diff mbox

Patch

commit bc3d6d30fd620ea1d7d286512f983a7a1ddb99c0
Author: Jonathan Wakely <jwakely@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();
+}
+