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();
+}
+