[Boost-bugs] [Boost C++ Libraries] #11826: float128.hpp: too aggressive NOTHROW on converting assignment operator

Subject: [Boost-bugs] [Boost C++ Libraries] #11826: float128.hpp: too aggressive NOTHROW on converting assignment operator
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2015-11-30 19:48:53


#11826: float128.hpp: too aggressive NOTHROW on converting assignment operator
-------------------------------------+----------------------------
 Reporter: martin.seemann@… | Owner: johnmaddock
     Type: Bugs | Status: new
Milestone: To Be Determined | Component: multiprecision
  Version: Boost Development Trunk | Severity: Regression
 Keywords: float128 nothrow |
-------------------------------------+----------------------------
 In order to fix another issue, commit
 https://github.com/boostorg/multiprecision/commit/9927d49cb9d87c022c3ac49b3c8d84ce55ab7dc4
 introduced several unconditional BOOST_NOTHROWs in float128.hpp.
 In my opinion, at least some of them are problematic, especially for the
 assignment operator (line 150) and the conversion constructor (line 147).
 Both support initialization from any type implicitly convertible to the
 underlying float128_type. However, implicit conversion routines might
 throw, as demonstrated by the following example program:


 {{{
 // g++ -std=c++11 exception_float128.cpp -o exception_float128 -fext-
 numeric-literals -lquadmath
 #include <iostream>
 #include <stdexcept>
 #include <boost/multiprecision/float128.hpp>

 struct outer {
         template <typename T> struct inner {
                 T operator()() const {
                         throw std::runtime_error("Bad stuff happened");
                         return T{0};
                 }
         };

         template <typename Target, typename = typename
 std::enable_if<!std::is_same<Target, const char *>::value>::type> operator
 Target() const {
                 return inner<Target>()();
         }
 };

 int main() {
         boost::multiprecision::float128 destination;
         outer source;
         try {
                 destination = source;
         } catch (const std::exception &e) {
                 std::cerr << "caught exception: " << e.what() << "\n";
         }
         return 0;
 }
 }}}


 Compiled with recent boost, this code std::terminate's. If BOOST_NOTHROW
 in float128.hpp:150 is replaced by
 BOOST_NOEXCEPT_IF(noexcept(std::declval<float128_type&>() =
 std::declval<const T&>())), the
 exception is caught as expected.
 Such conditional noexcept specifiers might be required in some more
 places, provided there isn't a policy that I am unaware of, which forbids
 implicit conversion operators to throw.

 (BTW: the above code is not just a twisted mockup. I hit the problem while
 developing a conversion library that uses the "template <typename T>
 operator T()" trick to let the compiler deduce the target type
 automatically. An appropriate functor is then selected that implements the
 actual conversion or throws, if no suitable source data is provided.)

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/11826>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:19 UTC