Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Potential regression: incomplete type in tag_of is a hard error #170

Closed
ldionne opened this issue Feb 27, 2018 · 4 comments
Closed

Potential regression: incomplete type in tag_of is a hard error #170

ldionne opened this issue Feb 27, 2018 · 4 comments

Comments

@ldionne
Copy link
Member

ldionne commented Feb 27, 2018

This issue was initially reported as boostorg/hana#386. The following is a hard error in Boost trunk:

#include <boost/fusion/include/tag_of.hpp>
struct incomplete;
using X = ::boost::fusion::traits::tag_of<incomplete>::type;

int main() { }

I believe this started happening with boostorg/type_traits@ac35139. fusion::tag_of is using boost::is_convertible, which requires its input to be a complete type, but I don't think it is documented anywhere that tags must be complete types. Possible workarounds are

  1. Only call is_convertible if boost::is_complete is true
  2. Request that tags be complete types (but that's a breaking change)
  3. Reimplement the is_convertible without the assertion

I think (1) is the best solution, even though I am skeptical that a is_complete trait can even be implemented without compiler support. But since Boost.TypeTraits provides it, it seems like it's possible.

The full error message (with Clang) is:

In file included from [snip].cpp:5:
In file included from [snip]/boost/fusion/include/tag_of.hpp:11:
In file included from [snip]/boost/fusion/support/tag_of.hpp:14:
In file included from [snip]/boost/fusion/support/detail/is_mpl_sequence.hpp:16:
[snip]/boost/type_traits/is_convertible.hpp:498:4: error: static_assert failed "From argument type to is_convertible must be a complete type"
   BOOST_STATIC_ASSERT_MSG(boost::is_complete<From>::value || boost::is_void<From>::value || boost::is_array<From>::value, "From argument type to is_convertible must be a complete type");
   ^                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[snip]/boost/static_assert.hpp:31:45: note: expanded from macro 'BOOST_STATIC_ASSERT_MSG'
#     define BOOST_STATIC_ASSERT_MSG( ... ) static_assert(__VA_ARGS__)
                                            ^             ~~~~~~~~~~~
[snip]/boost/mpl/aux_/nested_type_wknd.hpp:27:7: note: in instantiation of template class 'boost::is_convertible<incomplete, boost::fusion::detail::from_sequence_convertible_type>' requested here
    : T::type
      ^
[snip]/boost/mpl/not.hpp:41:11: note: in instantiation of template class 'boost::mpl::aux::nested_type_wknd<boost::is_convertible<incomplete, boost::fusion::detail::from_sequence_convertible_type> >' requested here
          BOOST_MPL_AUX_NESTED_TYPE_WKND(T)::value
          ^
[snip]/boost/mpl/aux_/nested_type_wknd.hpp:38:24: note: expanded from macro 'BOOST_MPL_AUX_NESTED_TYPE_WKND'
    ::boost::mpl::aux::nested_type_wknd<T> \
                       ^
[snip]/boost/mpl/aux_/nested_type_wknd.hpp:27:7: note: in instantiation of template class 'boost::mpl::not_<boost::is_convertible<incomplete, boost::fusion::detail::from_sequence_convertible_type> >' requested here
    : T::type
      ^
[snip]/boost/mpl/aux_/preprocessed/gcc/and.hpp:51:11: note: in instantiation of template class 'boost::mpl::aux::nested_type_wknd<boost::mpl::not_<boost::is_convertible<incomplete, boost::fusion::detail::from_sequence_convertible_type> > >' requested here
          BOOST_MPL_AUX_NESTED_TYPE_WKND(T1)::value
          ^
[snip]/boost/mpl/aux_/nested_type_wknd.hpp:38:24: note: expanded from macro 'BOOST_MPL_AUX_NESTED_TYPE_WKND'
    ::boost::mpl::aux::nested_type_wknd<T> \
                       ^
[snip]/boost/fusion/support/detail/is_mpl_sequence.hpp:22:11: note: in instantiation of template class 'boost::mpl::and_<boost::mpl::not_<boost::is_convertible<incomplete, boost::fusion::detail::from_sequence_convertible_type> >, boost::mpl::is_sequence<incomplete>, mpl_::bool_<true>, mpl_::bool_<true>, mpl_::bool_<true> >' requested here
        : mpl::and_<
          ^
[snip]/boost/mpl/if.hpp:63:68: note: in instantiation of template class 'boost::fusion::detail::is_mpl_sequence<incomplete>' requested here
          BOOST_MPL_AUX_STATIC_CAST(bool, BOOST_MPL_AUX_VALUE_WKND(T1)::value)
                                                                   ^
[snip]/boost/fusion/support/tag_of.hpp:53:18: note: in instantiation of template class 'boost::mpl::if_<boost::fusion::detail::is_mpl_sequence<incomplete>, boost::mpl::identity<boost::fusion::mpl_sequence_tag>, boost::mpl::identity<boost::fusion::non_fusion_tag> >' requested here
          : mpl::if_<fusion::detail::is_mpl_sequence<Sequence>,
                 ^
[snip]/boost/fusion/support/tag_of.hpp:71:15: note: in instantiation of template class 'boost::fusion::detail::tag_of_impl<incomplete, void>' requested here
            : boost::fusion::detail::tag_of_impl<Sequence, Active>
              ^
[snip].cpp:7:36: note: in instantiation of template class 'boost::fusion::traits::tag_of<incomplete, void>' requested here
using X = ::boost::fusion::traits::tag_of<incomplete>::type;
                                   ^
@Flast
Copy link
Collaborator

Flast commented Mar 1, 2018

Is hana tag a sequence? It seems hana passes tag type to tag_of.

../../../boost/fusion/support/tag_of.hpp:70:16: required from ‘struct boost::fusion::traits::tag_of<boost::hana::ext::boost::fusion::deque_tag, void>’ (from boostorg/hana#386)

@ldionne
Copy link
Member Author

ldionne commented Mar 1, 2018

This is expected. hana::tag_of is idempotent, so hana::tag_of<boost::hana::ext::boost::fusion::deque_tag>::type should be boost::hana::ext::boost::fusion::deque_tag. More precisely, here is what happens:

hana::any_of(fusion::make_deque(...), pred)
using Tag = hana::tag_of<decltype(fusion::make_deque(...))>::type;
if constexpr (hana::Searchable<Tag>::value) {
  // do something
}

But then, hana::Searchable<Tag> is really hana::Searchable<boost::hana::ext::boost::fusion::deque_tag>, which does (with Tag = boost::hana::ext::boost::fusion::deque_tag:

hana::integral_constant<bool,
  !is_default<any_of_impl<hana::tag_of<Tag>::type>>::value &&
  !is_default<find_if_impl<tag_of<Tag>::type>>::value
>

Here, tag_of<Tag>::type is expected to return just Tag if it's already a tag, but it hard-errors when the fusion adapters are included and the tag is incomplete, because we probe for whether the Tag is a fusion tag in that case.

Regardless of Hana's adapters, other clients of Fusion may have been using incomplete types for tags since this wasn't documented anywhere.

@djowel
Copy link
Member

djowel commented Mar 1, 2018

By design, we should be able to use incomplete types.

@Flast
Copy link
Collaborator

Flast commented Mar 2, 2018

OK. Additionally, the change also should be applied to fusion::is_sequence.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants