Refs #3395. Optional construction and assignment now works correctly for types with overridden operator&. Also silenced some GCC warnings about broken strict aliasing rules.

[SVN r67020]
This commit is contained in:
Andrey Semashev
2010-12-05 14:43:18 +00:00
parent ab01dfff7e
commit f88c8ae423

View File

@ -11,12 +11,12 @@
// //
// Revisions: // Revisions:
// 27 Apr 2008 (improved swap) Fernando Cacciola, Niels Dekker, Thorsten Ottosen // 27 Apr 2008 (improved swap) Fernando Cacciola, Niels Dekker, Thorsten Ottosen
// //
#ifndef BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP #ifndef BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP
#define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP #define BOOST_OPTIONAL_OPTIONAL_FLC_19NOV2002_HPP
#include<new> #include <new>
#include<algorithm> #include <algorithm>
#include "boost/config.hpp" #include "boost/config.hpp"
#include "boost/assert.hpp" #include "boost/assert.hpp"
@ -31,6 +31,7 @@
#include "boost/mpl/not.hpp" #include "boost/mpl/not.hpp"
#include "boost/detail/reference_content.hpp" #include "boost/detail/reference_content.hpp"
#include "boost/none.hpp" #include "boost/none.hpp"
#include "boost/utility/addressof.hpp"
#include "boost/utility/compare_pointees.hpp" #include "boost/utility/compare_pointees.hpp"
#include "boost/utility/in_place_factory.hpp" #include "boost/utility/in_place_factory.hpp"
@ -110,7 +111,12 @@ template <class T>
class aligned_storage class aligned_storage
{ {
// Borland ICEs if unnamed unions are used for this! // Borland ICEs if unnamed unions are used for this!
union dummy_u union
#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
// This works around GCC warnings about breaking strict aliasing rules when casting storage address to T*
__attribute__((may_alias))
#endif
dummy_u
{ {
char data[ sizeof(T) ]; char data[ sizeof(T) ];
BOOST_DEDUCED_TYPENAME type_with_alignment< BOOST_DEDUCED_TYPENAME type_with_alignment<
@ -119,8 +125,13 @@ class aligned_storage
public: public:
void const* address() const { return &dummy_.data[0]; } #if defined(__GNUC__) && !defined(__INTEL_COMPILER)
void * address() { return &dummy_.data[0]; } void const* address() const { return &dummy_; }
void * address() { return &dummy_; }
#else
void const* address() const { return dummy_.data; }
void * address() { return dummy_.data; }
#endif
} ; } ;
template<class T> template<class T>
@ -154,7 +165,7 @@ class optional_base : public optional_tag
typedef typedef
#if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564)) #if !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x564))
BOOST_DEDUCED_TYPENAME BOOST_DEDUCED_TYPENAME
#endif #endif
::boost::detail::make_reference_content<T>::type internal_type ; ::boost::detail::make_reference_content<T>::type internal_type ;
typedef aligned_storage<internal_type> storage_type ; typedef aligned_storage<internal_type> storage_type ;
@ -205,7 +216,7 @@ class optional_base : public optional_tag
{ {
construct(val); construct(val);
} }
// Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialzed optional<T>. // Creates an optional<T> initialized with 'val' IFF cond is true, otherwise creates an uninitialzed optional<T>.
// Can throw if T::T(T const&) does // Can throw if T::T(T const&) does
optional_base ( bool cond, argument_type val ) optional_base ( bool cond, argument_type val )
@ -426,8 +437,22 @@ class optional_base : public optional_tag
private : private :
// internal_type can be either T or reference_content<T> // internal_type can be either T or reference_content<T>
#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
// This workaround is supposed to silence GCC warnings about broken strict aliasing rules
internal_type const* get_object() const
{
union { void const* ap_pvoid; internal_type const* as_ptype; } caster = { m_storage.address() };
return caster.as_ptype;
}
internal_type * get_object()
{
union { void* ap_pvoid; internal_type* as_ptype; } caster = { m_storage.address() };
return caster.as_ptype;
}
#else
internal_type const* get_object() const { return static_cast<internal_type const*>(m_storage.address()); } internal_type const* get_object() const { return static_cast<internal_type const*>(m_storage.address()); }
internal_type * get_object() { return static_cast<internal_type *> (m_storage.address()); } internal_type * get_object() { return static_cast<internal_type *> (m_storage.address()); }
#endif
// reference_content<T> lacks an implicit conversion to T&, so the following is needed to obtain a proper reference. // reference_content<T> lacks an implicit conversion to T&, so the following is needed to obtain a proper reference.
reference_const_type dereference( internal_type const* p, is_not_reference_tag ) const { return *p ; } reference_const_type dereference( internal_type const* p, is_not_reference_tag ) const { return *p ; }
@ -518,7 +543,7 @@ class optional : public optional_detail::optional_base<T>
// Depending on the above some T ctor is called. // Depending on the above some T ctor is called.
// Can throw is the resolved T ctor throws. // Can throw is the resolved T ctor throws.
template<class Expr> template<class Expr>
explicit optional ( Expr const& expr ) : base(expr,&expr) {} explicit optional ( Expr const& expr ) : base(expr,boost::addressof(expr)) {}
#endif #endif
// Creates a deep copy of another optional<T> // Creates a deep copy of another optional<T>
@ -532,9 +557,9 @@ class optional : public optional_detail::optional_base<T>
// Assigns from an expression. See corresponding constructor. // Assigns from an expression. See corresponding constructor.
// Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED // Basic Guarantee: If the resolved T ctor throws, this is left UNINITIALIZED
template<class Expr> template<class Expr>
optional& operator= ( Expr expr ) optional& operator= ( Expr const& expr )
{ {
this->assign_expr(expr,&expr); this->assign_expr(expr,boost::addressof(expr));
return *this ; return *this ;
} }
#endif #endif
@ -595,7 +620,7 @@ class optional : public optional_detail::optional_base<T>
// Returns a copy of the value if this is initialized, 'v' otherwise // Returns a copy of the value if this is initialized, 'v' otherwise
reference_const_type get_value_or ( reference_const_type v ) const { return this->is_initialized() ? get() : v ; } reference_const_type get_value_or ( reference_const_type v ) const { return this->is_initialized() ? get() : v ; }
reference_type get_value_or ( reference_type v ) { return this->is_initialized() ? get() : v ; } reference_type get_value_or ( reference_type v ) { return this->is_initialized() ? get() : v ; }
// Returns a pointer to the value if this is initialized, otherwise, // Returns a pointer to the value if this is initialized, otherwise,
// the behaviour is UNDEFINED // the behaviour is UNDEFINED
// No-throw // No-throw
@ -612,22 +637,22 @@ class optional : public optional_detail::optional_base<T>
// No-throw // No-throw
operator unspecified_bool_type() const { return this->safe_bool() ; } operator unspecified_bool_type() const { return this->safe_bool() ; }
// This is provided for those compilers which don't like the conversion to bool // This is provided for those compilers which don't like the conversion to bool
// on some contexts. // on some contexts.
bool operator!() const { return !this->is_initialized() ; } bool operator!() const { return !this->is_initialized() ; }
} ; } ;
// Returns optional<T>(v) // Returns optional<T>(v)
template<class T> template<class T>
inline inline
optional<T> make_optional ( T const& v ) optional<T> make_optional ( T const& v )
{ {
return optional<T>(v); return optional<T>(v);
} }
// Returns optional<T>(cond,v) // Returns optional<T>(cond,v)
template<class T> template<class T>
inline inline
optional<T> make_optional ( bool cond, T const& v ) optional<T> make_optional ( bool cond, T const& v )
{ {
return optional<T>(cond,v); return optional<T>(cond,v);