From 196b8e7ea06e3167fda5708425f01632417546c0 Mon Sep 17 00:00:00 2001 From: Fernando Cacciola Date: Wed, 29 Jan 2003 19:48:43 +0000 Subject: [PATCH] Additional portability fixes (for VC6.0,VC7.0 and Intel C++ 7.0) [SVN r17082] --- include/boost/optional.hpp | 29 +++++++++++-- test/optional_test.cpp | 79 ++++++++++++++++++++++-------------- test/optional_test_fail3.cpp | 11 +++++ 3 files changed, 86 insertions(+), 33 deletions(-) diff --git a/include/boost/optional.hpp b/include/boost/optional.hpp index ca4a976..1a82a64 100644 --- a/include/boost/optional.hpp +++ b/include/boost/optional.hpp @@ -25,6 +25,27 @@ #include "boost/type_traits/alignment_of.hpp" #include "boost/type_traits/type_with_alignment.hpp" +#if BOOST_WORKAROUND(BOOST_MSVC, == 1200) +// VC6.0 has the following bug: +// When a templated assignment operator exist, an implicit conversion +// constructing an optional is used when assigment of the form: +// optional opt ; opt = T(...); +// is compiled. +// However, optional's ctor is _explicit_ and the assignemt shouldn't compile. +// Therefore, for VC6.0 templated assignment is disabled. +// +#define BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT +#endif + +#if BOOST_WORKAROUND(BOOST_MSVC, == 1300) +// VC7.0 has the following bug: +// When both a non-template and a template copy-ctor exist +// and the templated version is made 'explicit', the explicit is also +// given to the non-templated version, making the class non-implicitely-copyable. +// +#define BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR +#endif + namespace boost { namespace optional_detail @@ -74,8 +95,9 @@ class optional construct(val); } +#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR // NOTE: MSVC needs templated versions first - + // Creates a deep copy of another convertible optional // Requires a valid conversion from U to T. // Can throw if T::T(U const&) does @@ -87,6 +109,7 @@ class optional if ( rhs ) construct(*rhs); } +#endif // Creates a deep copy of another optional // Can throw if T::T(T const&) does @@ -98,10 +121,10 @@ class optional construct(*rhs); } - // No-throw (assuming T::~T() doesn't) ~optional() { destroy() ; } +#ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT // Assigns from another convertible optional (converts && deep-copies the rhs value) // Requires a valid conversion from U to T. // Basic Guarantee: If T::T( U const& ) throws, this is left UNINITIALIZED @@ -118,6 +141,7 @@ class optional } return *this ; } +#endif // Assigns from another optional (deep-copies the rhs value) // Basic Guarantee: If T::T( T const& ) throws, this is left UNINITIALIZED @@ -134,7 +158,6 @@ class optional return *this ; } - // Destroys the current value, if any, leaving this UNINITIALIZED // No-throw (assuming T::~T() doesn't) void reset() diff --git a/test/optional_test.cpp b/test/optional_test.cpp index c2d0139..f1e3e4a 100644 --- a/test/optional_test.cpp +++ b/test/optional_test.cpp @@ -54,7 +54,7 @@ void assertion_failed (char const * expr, char const * func, char const * file, using boost::optional ; -template inline void unused_variable ( T ) {} +template inline void unused_variable ( T const& ) {} #ifdef BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP using boost::swap ; @@ -63,7 +63,7 @@ using boost::get_pointer ; // MSVC6.0 does not support comparisons of optional against a literal null pointer value (0) // via the safe_bool operator. -#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1200 ) // 1200 == VC++ 6.0 +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1200) // 1200 == VC++ 6.0 #define BOOST_OPTIONAL_NO_NULL_COMPARE #endif @@ -237,7 +237,7 @@ inline void check_value_const ( optional const& opt, T const& v, T const& z ) template inline void check_value ( optional& opt, T const& v, T const& z ) { -#if defined(BOOST_MSVC) && (BOOST_MSVC <= 1200 ) // 1200 == VC++ 6.0 +#if BOOST_WORKAROUND(BOOST_MSVC, <= 1200) // 1200 == VC++ 6.0 // For some reason, VC6.0 is creating a temporary while evaluating (*opt == v), // so we need to turn throw on copy off first. reset_throw_on_copy( ARG(T) ) ; @@ -263,7 +263,7 @@ void test_basics( T const* ) { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - T z(-1); + T z(0); T a(1); @@ -366,7 +366,7 @@ void test_direct_value_manip( T const* ) { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - T x(1); + T x(3); optional const c_opt0(x) ; optional opt0(x); @@ -377,7 +377,7 @@ void test_direct_value_manip( T const* ) BOOST_CHECK( (*c_opt0).V() == x.V() ) ; BOOST_CHECK( (* opt0).V() == x.V() ) ; - T y(2); + T y(4); *opt0 = y ; BOOST_CHECK( (*opt0).V() == y.V() ) ; @@ -408,7 +408,7 @@ void test_uninitialized_access( T const* ) passed = false ; try { - T v(1) ; + T v(5) ; unused_variable(v); // This should throw because 'def' is uninitialized *def = v ; @@ -429,6 +429,10 @@ void test_uninitialized_access( T const* ) BOOST_CHECK(!passed); } +#if BOOST_WORKAROUND( BOOST_INTEL_CXX_VERSION, <= 700) // Intel C++ 7.0 +void prevent_buggy_optimization( bool v ) {} +#endif + // // Test Direct Initialization of optional for a T with throwing copy-ctor. // @@ -437,7 +441,7 @@ void test_throwing_direct_init( T const* ) { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - T a(1234); + T a(6); int count = get_instance_count( ARG(T) ) ; @@ -450,6 +454,18 @@ void test_throwing_direct_init( T const* ) // Attempt to copy construct 'a' and throw. // 'opt' won't be constructed. set_pending_copy( ARG(T) ) ; + +#if BOOST_WORKAROUND( BOOST_INTEL_CXX_VERSION, <= 700) // Intel C++ 7.0 + // Intel C++ 7.0 specific: + // For some reason, when "check_is_not_pending_copy", + // after the exception block is reached, + // X::pending_copy==true even though X's copy ctor set it to false. + // I guessed there is some sort of optimization bug, + // and it seems to be the since the following additional line just + // solves the problem (!?) + prevent_buggy_optimization(X::pending_copy); +#endif + optional opt(a) ; passed = true ; } @@ -468,7 +484,7 @@ void test_throwing_val_assign_on_uninitialized( T const* ) { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - T a(1234); + T a(7); int count = get_instance_count( ARG(T) ) ; @@ -503,9 +519,9 @@ void test_throwing_val_assign_on_initialized( T const* ) { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - T z(-1); - T a(1234); - T b(5678); + T z(0); + T a(8); + T b(9); int count = get_instance_count( ARG(T) ) ; @@ -551,8 +567,8 @@ void test_throwing_copy_initialization( T const* ) { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - T z(-1); - T a(1234); + T z(0); + T a(10); reset_throw_on_copy( ARG(T) ) ; @@ -593,8 +609,8 @@ void test_throwing_assign_to_uninitialized( T const* ) { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - T z(-1); - T a(1234); + T z(0); + T a(11); reset_throw_on_copy( ARG(T) ) ; @@ -633,9 +649,9 @@ void test_throwing_assign_to_initialized( T const* ) { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - T z(-1); - T a(1234); - T b(5678); + T z(0); + T a(12); + T b(13); reset_throw_on_copy( ARG(T) ) ; @@ -677,9 +693,9 @@ void test_no_throwing_swap( T const* ) { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - T z(-1); - T a(1234); - T b(5678); + T z(0); + T a(14); + T b(15); reset_throw_on_copy( ARG(T) ) ; @@ -720,8 +736,8 @@ void test_throwing_swap( T const* ) { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - T a(1234); - T b(5678); + T a(16); + T b(17); reset_throw_on_copy( ARG(T) ) ; @@ -787,9 +803,9 @@ void test_relops( T const* ) reset_throw_on_copy( ARG(T) ) ; - T v0(1); - T v1(2); - T v2(2); + T v0(18); + T v1(19); + T v2(19); optional def0 ; optional def1 ; @@ -881,18 +897,21 @@ void test_conversions() { TRACE( std::endl << BOOST_CURRENT_FUNCTION ); - char c = 123 ; +#ifndef BOOST_OPTIONAL_NO_CONVERTING_COPY_CTOR + char c = 20 ; optional opt0(c); - optional opt1(opt0); BOOST_CHECK(*opt1 == static_cast(c)); +#endif - float f = 1.234f ; +#ifndef BOOST_OPTIONAL_NO_CONVERTING_ASSIGNMENT + float f = 21.22f ; double d = f ; optional opt2(f) ; optional opt3 ; opt3 = opt2 ; BOOST_CHECK(*opt3 == d); +#endif } int test_main( int, char* [] ) diff --git a/test/optional_test_fail3.cpp b/test/optional_test_fail3.cpp index 8dee9e1..1e08364 100644 --- a/test/optional_test_fail3.cpp +++ b/test/optional_test_fail3.cpp @@ -17,9 +17,20 @@ // // THIS TEST SHOULD FAIL TO COMPILE // +#if BOOST_WORKAROUND( BOOST_INTEL_CXX_VERSION, <= 700) // Intel C++ 7.0 +// Interl C++ 7.0 incorrectly accepts the initialization "boost::optional opt = 3" +// even though the ctor is explicit (c.f. 12.3.1.2), so the test uses another form of +// copy-initialization: argument-passing (8.5.12) +void helper ( boost::optional ) ; +void test_explicit_constructor() +{ + helper(3) ; // ERROR: Ctor is explicit. +} +#else void test_explicit_constructor() { boost::optional opt = 3 ; // ERROR: Ctor is explicit. } +#endif