token used when constructing a ``std::random_device`` will now be ignored instead of
interpreted as a file to read entropy from.
+- ``std::valarray``'s unary operators ``!``, ``+``, ``~`` and ``-`` now return an expression
+ object instead of a ``valarray``. This was done to fix an issue where any expression involving
+ other ``valarray`` operators and one of these unary operators would end up with a dangling
+ reference. This is a potential ABI break for code that exposes ``std::valarray`` on an ABI
+ boundary, specifically if the return type of an ABI-boundary function is ``auto``-deduced
+ from an expression involving unary operators on ``valarray``. If you are concerned by this,
+ you can audit whether your executable or library exports any function that returns a
+ ``valarray``, and if so ensure that any such function uses ``std::valarray`` directly
+ as a return type instead of relying on the type of ``valarray``-expressions, which is
+ not guaranteed by the Standard anyway.
+
Build System Changes
--------------------
#endif // _LIBCPP_CXX03_LANG
// unary operators:
- valarray operator+() const;
- valarray operator-() const;
- valarray operator~() const;
- valarray<bool> operator!() const;
+ _LIBCPP_INLINE_VISIBILITY
+ __val_expr<_UnaryOp<__unary_plus<_Tp>, const valarray&> > operator+() const;
+ _LIBCPP_INLINE_VISIBILITY
+ __val_expr<_UnaryOp<negate<_Tp>, const valarray&> > operator-() const;
+ _LIBCPP_INLINE_VISIBILITY
+ __val_expr<_UnaryOp<__bit_not<_Tp>, const valarray&> > operator~() const;
+ _LIBCPP_INLINE_VISIBILITY
+ __val_expr<_UnaryOp<logical_not<_Tp>, const valarray&> > operator!() const;
// computed assignment:
_LIBCPP_INLINE_VISIBILITY
#endif // _LIBCPP_CXX03_LANG
template <class _Tp>
-valarray<_Tp>
+inline
+__val_expr<_UnaryOp<__unary_plus<_Tp>, const valarray<_Tp>&> >
valarray<_Tp>::operator+() const
{
- valarray<value_type> __r;
- size_t __n = size();
- if (__n)
- {
- __r.__begin_ = __r.__end_ = allocator<value_type>().allocate(__n);
- for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
- ::new ((void*)__r.__end_) value_type(+*__p);
- }
- return __r;
+ using _Op = _UnaryOp<__unary_plus<_Tp>, const valarray<_Tp>&>;
+ return __val_expr<_Op>(_Op(__unary_plus<_Tp>(), *this));
}
template <class _Tp>
-valarray<_Tp>
+inline
+__val_expr<_UnaryOp<negate<_Tp>, const valarray<_Tp>&> >
valarray<_Tp>::operator-() const
{
- valarray<value_type> __r;
- size_t __n = size();
- if (__n)
- {
- __r.__begin_ = __r.__end_ = allocator<value_type>().allocate(__n);
- for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
- ::new ((void*)__r.__end_) value_type(-*__p);
- }
- return __r;
+ using _Op = _UnaryOp<negate<_Tp>, const valarray<_Tp>&>;
+ return __val_expr<_Op>(_Op(negate<_Tp>(), *this));
}
template <class _Tp>
-valarray<_Tp>
+inline
+__val_expr<_UnaryOp<__bit_not<_Tp>, const valarray<_Tp>&> >
valarray<_Tp>::operator~() const
{
- valarray<value_type> __r;
- size_t __n = size();
- if (__n)
- {
- __r.__begin_ = __r.__end_ = allocator<value_type>().allocate(__n);
- for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
- ::new ((void*)__r.__end_) value_type(~*__p);
- }
- return __r;
+ using _Op = _UnaryOp<__bit_not<_Tp>, const valarray<_Tp>&>;
+ return __val_expr<_Op>(_Op(__bit_not<_Tp>(), *this));
}
template <class _Tp>
-valarray<bool>
+inline
+__val_expr<_UnaryOp<logical_not<_Tp>, const valarray<_Tp>&> >
valarray<_Tp>::operator!() const
{
- valarray<bool> __r;
- size_t __n = size();
- if (__n)
- {
- __r.__begin_ = __r.__end_ = allocator<bool>().allocate(__n);
- for (const value_type* __p = __begin_; __n; ++__r.__end_, ++__p, --__n)
- ::new ((void*)__r.__end_) bool(!*__p);
- }
- return __r;
+ using _Op = _UnaryOp<logical_not<_Tp>, const valarray<_Tp>&>;
+ return __val_expr<_Op>(_Op(logical_not<_Tp>(), *this));
}
template <class _Tp>