Bug 90415 - [9 Regression] std::is_copy_constructible<std::tuple<std::any>> is incomplete
Summary: [9 Regression] std::is_copy_constructible<std::tuple<std::any>> is incomplete
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 9.1.1
: P2 normal
Target Milestone: 9.5
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
: 91630 (view as bug list)
Depends on:
Blocks:
 
Reported: 2019-05-09 16:29 UTC by Paweł Dziepak
Modified: 2021-07-22 21:31 UTC (History)
9 users (show)

See Also:
Host:
Target:
Build:
Known to work: 8.3.0
Known to fail: 10.0, 9.1.0
Last reconfirmed: 2019-05-23 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Paweł Dziepak 2019-05-09 16:29:08 UTC
Compiler Explorer link: https://godbolt.org/z/RCoRVj

The following code:

```
#include <any>
#include <tuple>
#include <type_traits>

bool is_copy_constructible_tuple_any() {
    return std::is_copy_constructible<std::tuple<std::any>>::value;
}
```

when compiled with GCC 9.1 and `-Wall -Wextra -std=c++17` results in a rather elaborate error message:

```
In file included from /usr/include/c++/9/bits/move.h:55,
                 from /usr/include/c++/9/bits/nested_exception.h:40,
                 from /usr/include/c++/9/exception:144,
                 from /usr/include/c++/9/new:40,
                 from /usr/include/c++/9/any:37,
                 from test.cc:1:
/usr/include/c++/9/type_traits: In instantiation of ‘struct std::__and_<std::is_copy_constructible<std::tuple<std::any> >, std::is_constructible<std::tuple<std::any>, const std::tuple<std::any>&> >’:
/usr/include/c++/9/any:181:58:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_constructible<_Tp, _ValueType&&> >::value, bool>::type <anonymous>, typename std::enable_if<(! std::__is_in_place_type<_Tp>::value), bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = const std::tuple<std::any>&; _Tp = std::tuple<std::any>; _Mgr = std::any::_Manager_external<std::tuple<std::any> >; typename std::enable_if<std::__and_<std::is_copy_constructible<_Tp>, std::is_constructible<_Tp, _ValueType&&> >::value, bool>::type <anonymous> = <missing>; typename std::enable_if<(! std::__is_in_place_type<_Tp>::value), bool>::type <anonymous> = <missing>]’
/usr/include/c++/9/type_traits:931:12:   required from ‘struct std::is_constructible<std::tuple<std::any>, const std::tuple<std::any>&>’
/usr/include/c++/9/type_traits:943:12:   required from ‘struct std::__is_copy_constructible_impl<std::tuple<std::any>, true>’
/usr/include/c++/9/type_traits:949:12:   required from ‘struct std::is_copy_constructible<std::tuple<std::any> >’
test.cc:6:60:   required from here
/usr/include/c++/9/type_traits:131:12: error: incomplete type ‘std::is_copy_constructible<std::tuple<std::any> >’ used in nested name specifier
  131 |     struct __and_<_B1, _B2>
      |            ^~~~~~~~~~~~~~~~
/usr/include/c++/9/type_traits: In instantiation of ‘struct std::__and_<std::is_copy_constructible<std::tuple<std::any> >, std::__not_<std::is_constructible<std::tuple<std::any>, const std::tuple<std::any>&> >, std::__not_<std::__is_in_place_type<std::tuple<std::any> > > >’:
/usr/include/c++/9/type_traits:150:27:   required from ‘constexpr const bool std::__and_v<std::is_copy_constructible<std::tuple<std::any> >, std::__not_<std::is_constructible<std::tuple<std::any>, const std::tuple<std::any>&> >, std::__not_<std::__is_in_place_type<std::tuple<std::any> > > >’
/usr/include/c++/9/any:192:27:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<__and_v<std::is_copy_constructible<_Tp>, std::__not_<std::is_constructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = const std::tuple<std::any>&; _Tp = std::tuple<std::any>; _Mgr = std::any::_Manager_external<std::tuple<std::any> >; typename std::enable_if<__and_v<std::is_copy_constructible<_Tp>, std::__not_<std::is_constructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> = <missing>]’
/usr/include/c++/9/type_traits:931:12:   required from ‘struct std::is_constructible<std::tuple<std::any>, const std::tuple<std::any>&>’
/usr/include/c++/9/type_traits:943:12:   required from ‘struct std::__is_copy_constructible_impl<std::tuple<std::any>, true>’
/usr/include/c++/9/type_traits:949:12:   required from ‘struct std::is_copy_constructible<std::tuple<std::any> >’
test.cc:6:60:   required from here
/usr/include/c++/9/type_traits:136:12: error: incomplete type ‘std::is_copy_constructible<std::tuple<std::any> >’ used in nested name specifier
  136 |     struct __and_<_B1, _B2, _B3, _Bn...>
      |            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/9/type_traits: In instantiation of ‘constexpr const bool std::__and_v<std::is_copy_constructible<std::tuple<std::any> >, std::__not_<std::is_constructible<std::tuple<std::any>, const std::tuple<std::any>&> >, std::__not_<std::__is_in_place_type<std::tuple<std::any> > > >’:
/usr/include/c++/9/any:192:27:   required by substitution of ‘template<class _ValueType, class _Tp, class _Mgr, typename std::enable_if<__and_v<std::is_copy_constructible<_Tp>, std::__not_<std::is_constructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> > std::any::any(_ValueType&&) [with _ValueType = const std::tuple<std::any>&; _Tp = std::tuple<std::any>; _Mgr = std::any::_Manager_external<std::tuple<std::any> >; typename std::enable_if<__and_v<std::is_copy_constructible<_Tp>, std::__not_<std::is_constructible<_Tp, _ValueType&&> >, std::__not_<std::__is_in_place_type<_Tp> > >, bool>::type <anonymous> = <missing>]’
/usr/include/c++/9/type_traits:931:12:   required from ‘struct std::is_constructible<std::tuple<std::any>, const std::tuple<std::any>&>’
/usr/include/c++/9/type_traits:943:12:   required from ‘struct std::__is_copy_constructible_impl<std::tuple<std::any>, true>’
/usr/include/c++/9/type_traits:949:12:   required from ‘struct std::is_copy_constructible<std::tuple<std::any> >’
test.cc:6:60:   required from here
/usr/include/c++/9/type_traits:150:27: error: ‘value’ is not a member of ‘std::__and_<std::is_copy_constructible<std::tuple<std::any> >, std::__not_<std::is_constructible<std::tuple<std::any>, const std::tuple<std::any>&> >, std::__not_<std::__is_in_place_type<std::tuple<std::any> > > >’
  150 |     inline constexpr bool __and_v = __and_<_Bn...>::value;
      |                           
```
Comment 1 Rafael Avila de Espindola 2019-05-22 17:44:33 UTC
This bug was present when gcc 8 branched. It was fixed in the gcc 8 branch, but I guess it was never fixed on trunk.

On the gcc 8 branch it was fixed by r261463 (d26c6b8b0c6abba9a67b87a1d48f0c3165d021cc).
Comment 2 Rafael Avila de Espindola 2019-05-22 18:02:41 UTC
The bug is still present on trunk.
Comment 3 Rafael Avila de Espindola 2019-05-23 01:59:21 UTC
I see now that the corresponding commit on trunk was 31011b9a94fed33170c009292e82558336d1c4d7 (r261146).

At that revision, the test in this bug passes. There was a more recent regression on trunk on revision a9b768f8f4fd471e315623b23c4f9e83463bf92e (r270433).
Comment 4 Jonathan Wakely 2019-05-23 07:35:59 UTC
Thanks for the bisection.

Changing component to c++ for now, although it's possible a fix is needed in the library.
Comment 5 Jonathan Wakely 2019-07-01 12:19:21 UTC
I think this is a libstdc++ bug, because Clang has always rejected the example with any version of the libstdc++ headers. And I know what's going on, and might have a fix.
Comment 6 Lei YU 2019-08-08 06:59:09 UTC
This issue prevents using std::any with gmock, which I need it for the unit tests to pass the build.

There are related SO questions:
* https://stackoverflow.com/questions/57332965/incomplete-type-for-stdany-when-gmocking-interface
* https://stackoverflow.com/questions/57387245/using-stdany-with-gmock-result-in-different-behavior-on-gcc-79

@Jonathan Wakely Is there a quick fix for this? I would like to test it.
Comment 7 Lei YU 2019-08-08 07:57:31 UTC
Additional information.

std::experimental::fundamentals_v1::any has no problem, so the below code compiles fine.

```
#include <experimental/any>
#include <tuple>
#include <type_traits>

bool is_copy_constructible_tuple_any() {
    return std::is_copy_constructible<std::tuple<std::experimental::any>>::value;
}
```
Comment 8 Jonathan Wakely 2019-08-08 11:17:53 UTC
(In reply to Lei YU from comment #6)
> @Jonathan Wakely Is there a quick fix for this? I would like to test it.

If I had a fix I would have committed it.
Comment 9 Jonathan Wakely 2019-08-16 15:49:25 UTC
(In reply to Lei YU from comment #7)
> Additional information.
> 
> std::experimental::fundamentals_v1::any has no problem, so the below code
> compiles fine.

The difference is that std::experimental::any doesn't constrain the any(T&&) constructor on is_copy_constructible<T>, instead it just makes it a hard error (using a static assert in the constructor body).

std::any has to SFINAE the any(T&&) constructor away if T is not copy constructible, which leads to a cycle when that constructor is being considered during instantiation of is_copy_constructible<T>.
Comment 10 Jakub Jelinek 2020-03-12 11:58:51 UTC
GCC 9.3.0 has been released, adjusting target milestone.
Comment 11 Barry Revzin 2020-03-26 15:11:28 UTC
Here's an interesting reduction:

#include <type_traits>
struct any {
    any();
    any(any const&);
  template <class ValueType
            , class Tp = std::decay_t<ValueType>
            , class = std::enable_if_t<
                !std::is_same<Tp, any>::value
                && std::is_copy_constructible<Tp>::value
#ifdef LIBSTDCXX
                && std::is_constructible<Tp, ValueType>::value
#endif        
        >
    >
  any(ValueType&& value);    
};

struct X {
  X(X const&);
  X(any);
};
static_assert(std::is_copy_constructible_v<X>);


This compiles fine, fails if you add -DLIBSTDCXX. I laid it out this way because libstdc++ has that check but libc++ doesn't. Although, this is especially weird because in this program, there is only one instantiation of any's constructor template and it's with ValueType=X const&, which means that we're checking is_copy_constructible<X> && is_constructible<X, X const&>... which should be identical and yet are somehow not.
Comment 12 Jonathan Wakely 2020-04-23 22:37:02 UTC
*** Bug 91630 has been marked as a duplicate of this bug. ***
Comment 13 GCC Commits 2020-04-24 00:01:50 UTC
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:d1462b0782555354b4480e1f46498586d5882972

commit r10-7935-gd1462b0782555354b4480e1f46498586d5882972
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Apr 24 00:54:20 2020 +0100

    libstdc++: Fix constructor constraints for std::any  (PR 90415)
    
    This removes a non-standard extension to std::any which causes errors
    for valid code, due to recursive instantiation of a trait that isn't
    supposed to be in the constraints.
    
    It also removes some incorrect constraints on the in_place_type<T>
    constructors and emplace members, which were preventing creating a
    std::any object with another std::any as the contained value.
    
    2020-04-24  Kamlesh Kumar  <kamleshbhalui@gmail.com>
                Jonathan Wakely  <jwakely@redhat.com>
    
            PR libstdc++/90415
            PR libstdc++/92156
            * include/std/any (any): Rename template parameters for consistency
            with the standard.
            (any::_Decay): Rename to _Decay_if_not_any.
            (any::any(T&&):: Remove is_constructible from constraints. Remove
            non-standard overload.
            (any::any(in_place_type_t<T>, Args&&...))
            (any::any(in_place_type_t<T>, initializer_list<U>, Args&&...))
            (any::emplace(Args&&...))
            (any::emplace(initializer_list<U>, Args&&...)):
            Use decay_t instead of _Decay.
            * testsuite/20_util/any/cons/90415.cc: New test.
            * testsuite/20_util/any/cons/92156.cc: New Test.
            * testsuite/20_util/any/misc/any_cast_neg.cc: Make dg-error directives
            more robust.
            * testsuite/20_util/any/modifiers/92156.cc: New test.
Comment 14 Jonathan Wakely 2020-04-24 00:06:52 UTC
Fixed on master so far, backport to follow soon.
Comment 15 Bernd Baumanns 2020-07-23 22:23:10 UTC
I have nearly the same issue (g++ compiles fine, but clang++ not). Not with std::any as tuple argument, but some references to other tuple types.

I "solved" it, by using my own std::is_copy_constructible.

using my_is_copy_constructible = std::is_constructible_v<T, std::add_lvalue_reference_t<const T>>;
Comment 16 Richard Biener 2021-06-01 08:14:09 UTC
GCC 9.4 is being released, retargeting bugs to GCC 9.5.
Comment 17 GCC Commits 2021-07-22 21:28:57 UTC
The releases/gcc-9 branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:14597b680a24b6f7375e4470dea935da9c369feb

commit r9-9638-g14597b680a24b6f7375e4470dea935da9c369feb
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Fri Apr 24 00:54:20 2020 +0100

    libstdc++: Fix constructor constraints for std::any  (PR 90415)
    
    This removes a non-standard extension to std::any which causes errors
    for valid code, due to recursive instantiation of a trait that isn't
    supposed to be in the constraints.
    
    It also removes some incorrect constraints on the in_place_type<T>
    constructors and emplace members, which were preventing creating a
    std::any object with another std::any as the contained value.
    
    2020-04-24  Kamlesh Kumar  <kamleshbhalui@gmail.com>
                Jonathan Wakely  <jwakely@redhat.com>
    
            PR libstdc++/90415
            PR libstdc++/92156
            * include/std/any (any): Rename template parameters for consistency
            with the standard.
            (any::_Decay): Rename to _Decay_if_not_any.
            (any::any(T&&)): Remove is_constructible from constraints. Remove
            non-standard overload.
            (any::any(in_place_type_t<T>, Args&&...))
            (any::any(in_place_type_t<T>, initializer_list<U>, Args&&...))
            (any::emplace(Args&&...))
            (any::emplace(initializer_list<U>, Args&&...)):
            Use decay_t instead of _Decay.
            * testsuite/20_util/any/cons/90415.cc: New test.
            * testsuite/20_util/any/cons/92156.cc: New Test.
            * testsuite/20_util/any/misc/any_cast_neg.cc: Make dg-error directives
            more robust.
            * testsuite/20_util/any/modifiers/92156.cc: New test.
    
    (cherry picked from commit d1462b0782555354b4480e1f46498586d5882972)
Comment 18 Jonathan Wakely 2021-07-22 21:31:04 UTC
Fixed for 9.5 too.