mpark / variant

C++17 `std::variant` for C++11/14/17
https://mpark.github.io/variant
Boost Software License 1.0
664 stars 87 forks source link

noexcept compiler warning with gcc #42

Closed tboyce021 closed 6 years ago

tboyce021 commented 6 years ago

I'm getting a noexcept warning when using this with gcc. I've tried gcc 5.4.1, 6.3.0, and 7.2.0 all on Ubuntu 16.04 and get this warning on all of them. I'm using the 1.3.0 single header and compiling with the -std=c++11 flag.

This is the shortest example that I get the warning with:

#include "variant.hpp"

int main()
{
    mpark::visit([](bool&&) noexcept {}, mpark::variant<bool>());
    return 0;
}

It seems to be caused by using a visitor that doesn't throw an exception. Simply adding throw; to the lambda body and removing noexcept makes the warning go away, i.e. the following doesn't generate a warning:

mpark::visit([](bool&&) { throw 42; }, mpark::variant<bool>());

I've done a little bit of digging and can get rid of the warning by messing with

#define RETURN(...)                                          \
  noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { \
    return __VA_ARGS__;                                      \
  }

If I change noexcept(noexcept(__VA_ARGS__)) to virtually anything else, noexcept(true), noexcept(false), noexcept, or just remove it entirely, I no longer get the warning. I've gotten to the point where I'm not sure if this is a bug in the library, a compiler bug, or just me not understanding noexcept.

Here is the compiler output:

In file included from main.cpp:1:0:
variant.hpp: In instantiation of ‘constexpr decltype (forward<F>(f)((forward<As>)(mpark::lib::cpp17::invoke::as)...)) mpark::lib::cpp17::invoke(F&&, As&& ...) [with F = mpark::detail::visitation::variant::value_visitor<main()::<lambda(bool&&)> >; As = {mpark::detail::alt<0u, bool>}; decltype (forward<F>(f)((forward<As>)(mpark::lib::cpp17::invoke::as)...)) = void]’:
variant.hpp:1077:15:   required from ‘struct mpark::detail::visitation::base::dispatcher<0u>::impl<mpark::detail::visitation::variant::value_visitor<main()::<lambda(bool&&)> >&&, mpark::detail::base<(mpark::detail::Trait)0, bool>&&>’
variant.hpp:1085:11:   required by substitution of ‘template<class F, class ... Vs, unsigned int ...Is> static constexpr mpark::lib::cpp14::decay_t<decltype (& typename mpark::detail::visitation::base::dispatcher<Is ...>::impl<F, Vs ...>::dispatch)> mpark::detail::visitation::base::make_dispatch(mpark::lib::cpp14::index_sequence<Is ...>) [with F = mpark::detail::visitation::variant::value_visitor<main()::<lambda(bool&&)> >&&; Vs = {mpark::detail::base<(mpark::detail::Trait)0, bool>&&}; unsigned int ...Is = {0u}]’
variant.hpp:1140:15:   required from ‘struct mpark::detail::visitation::base::make_fmatrix_impl<mpark::detail::visitation::variant::value_visitor<main()::<lambda(bool&&)> >&&, mpark::detail::base<(mpark::detail::Trait)0, bool>&&>::impl<mpark::lib::cpp14::integer_sequence<unsigned int, 0u> >’
variant.hpp:1146:15:   required from ‘struct mpark::detail::visitation::base::make_fmatrix_impl<mpark::detail::visitation::variant::value_visitor<main()::<lambda(bool&&)> >&&, mpark::detail::base<(mpark::detail::Trait)0, bool>&&>::impl<mpark::lib::cpp14::integer_sequence<unsigned int>, mpark::lib::cpp14::integer_sequence<unsigned int, 0u> >’
variant.hpp:1153:11:   [ skipping 2 instantiation contexts, use -ftemplate-backtrace-limit=0 to disable ]
variant.hpp:1188:44:   required from ‘struct mpark::detail::visitation::fmatrix<mpark::detail::visitation::variant::value_visitor<main()::<lambda(bool&&)> >&&, mpark::detail::base<(mpark::detail::Trait)0, bool>&&>’
variant.hpp:1212:11:   required by substitution of ‘template<class Visitor, class ... Vs> static constexpr decltype (mpark::detail::visitation::base::at(mpark::detail::visitation::fmatrix<Visitor&&, decltype (as_base(forward<Vs>(vs)))...>::value, mpark::detail::visitation::alt::visit_alt::vs.index()...)(forward<Visitor>(visitor), as_base((forward<Vs>)(mpark::detail::visitation::alt::visit_alt::vs))...)) mpark::detail::visitation::alt::visit_alt(Visitor&&, Vs&& ...) [with Visitor = mpark::detail::visitation::variant::value_visitor<main()::<lambda(bool&&)> >; Vs = {mpark::detail::impl<bool>}]’
variant.hpp:1271:11:   required by substitution of ‘template<class Visitor, class ... Vs> static constexpr decltype (mpark::detail::visitation::alt::visit_alt(forward<Visitor>(visitor), (forward<Vs>)(mpark::detail::visitation::variant::visit_alt::vs).impl_ ...)) mpark::detail::visitation::variant::visit_alt(Visitor&&, Vs&& ...) [with Visitor = mpark::detail::visitation::variant::value_visitor<main()::<lambda(bool&&)> >; Vs = {mpark::variant<bool>}]’
variant.hpp:1286:11:   required by substitution of ‘template<class Visitor, class ... Vs> static constexpr decltype (mpark::detail::visitation::variant::visit_alt(mpark::detail::visitation::variant::make_value_visitor(forward<Visitor>(visitor)), (forward<Vs>)(mpark::detail::visitation::variant::visit_value::vs)...)) mpark::detail::visitation::variant::visit_value(Visitor&&, Vs&& ...) [with Visitor = main()::<lambda(bool&&)>; Vs = {mpark::variant<bool>}]’
variant.hpp:2342:5:   required by substitution of ‘template<class Visitor, class ... Vs> constexpr decltype (((mpark::detail::all(mpark::lib::cpp14::array<bool, sizeof... (Vs)>{{!mpark::visit::vs.valueless_by_exception()...}}) ? (void)(0) : mpark::throw_bad_variant_access()), mpark::detail::visitation::variant::visit_value(forward<Visitor>(visitor), (forward<Vs>)(mpark::visit::vs)...))) mpark::visit(Visitor&&, Vs&& ...) [with Visitor = main()::<lambda(bool&&)>; Vs = {mpark::variant<bool>}]’
main.cpp:5:64:   required from here
variant.hpp:545:29: error: noexcept-expression evaluates to ‘false’ because of a call to ‘constexpr decltype (mpark::detail::visitation::variant::visit_exhaustive_visitor_check<Visitor, decltype (forward<Alts>(alts).value)...>{}(forward<Visitor>(((const mpark::detail::visitation::variant::value_visitor<Visitor>*)this)->mpark::detail::visitation::variant::value_visitor<Visitor>::visitor_), (forward<Alts>)(mpark::detail::visitation::variant::value_visitor::operator()::alts).value ...)) mpark::detail::visitation::variant::value_visitor<Visitor>::operator()(Alts&& ...) const [with Alts = {mpark::detail::alt<0u, bool>}; Visitor = main()::<lambda(bool&&)>; decltype (mpark::detail::visitation::variant::visit_exhaustive_visitor_check<Visitor, decltype (forward<Alts>(alts).value)...>{}(forward<Visitor>(((const mpark::detail::visitation::variant::value_visitor<Visitor>*)this)->mpark::detail::visitation::variant::value_visitor<Visitor>::visitor_), (forward<Alts>)(mpark::detail::visitation::variant::value_visitor::operator()::alts).value ...)) = void]’ [-Werror=noexcept]
       inline constexpr auto invoke(F &&f, As &&... as)
                             ^
variant.hpp:1245:42: error: but ‘constexpr decltype (mpark::detail::visitation::variant::visit_exhaustive_visitor_check<Visitor, decltype (forward<Alts>(alts).value)...>{}(forward<Visitor>(((const mpark::detail::visitation::variant::value_visitor<Visitor>*)this)->mpark::detail::visitation::variant::value_visitor<Visitor>::visitor_), (forward<Alts>)(mpark::detail::visitation::variant::value_visitor::operator()::alts).value ...)) mpark::detail::visitation::variant::value_visitor<Visitor>::operator()(Alts&& ...) const [with Alts = {mpark::detail::alt<0u, bool>}; Visitor = main()::<lambda(bool&&)>; decltype (mpark::detail::visitation::variant::visit_exhaustive_visitor_check<Visitor, decltype (forward<Alts>(alts).value)...>{}(forward<Visitor>(((const mpark::detail::visitation::variant::value_visitor<Visitor>*)this)->mpark::detail::visitation::variant::value_visitor<Visitor>::visitor_), (forward<Alts>)(mpark::detail::visitation::variant::value_visitor::operator()::alts).value ...)) = void]’ does not throw; perhaps it should be declared ‘noexcept’ [-Werror=noexcept]
           inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const
tboyce021 commented 6 years ago

I can also get rid of the warning by adding noexcept(noexcept(__VA_ARGS__)) to DECLTYPE_AUTO_RETURN used by value_visitor::operator() and just noexcept to visitation::base::at.

That seems to work for me. Throwing from my lambda without noexcept on it propagates the exception while throwing with noexcept on the lambda calls terminate like I would expect. But I'm not sure if that's sufficient so someone else will need to look into this. Hopefully my investigation helps though :smiley: .

tboyce021 commented 6 years ago

Alright, upon further investigation, I appear to only be getting this with gcc 5.4.1 and 6.3.0. It seems 7.2.0 doesn't generate this warning.

mpark commented 6 years ago

Thanks for the report! I'll try to get around to looking at this before the weekend.

mpark commented 6 years ago

Fixed by: bc5d147d59e9132b54837cb226321ebb08c2e9b9 , 2d4503d88f97d880e2817095b27dc3e66646b577, 7d9454be276ad69e407db6e51aab98c995a8cc00, f6638fd18ca6badb421efdbb5442f140d1f76f66