The example in the PR is a sneaky little problem. When <valarray> is included the following overload is declared:
template<typename _Tp> _Expr</* here be expression templates */> operator<<(const _Tp& __t, const valarray<_Tp>& __v); This is a candidate function for any "a << b" expression with namespace std as an associated namespace. In order to do overload resolution valarray<decltype(a)> gets instantiated to see if there is a conversion from decltype(b). When decltype(a) is an abstract type valarray<decltype(a)> results in an error outside the immediate context, and overload resolution stops with an error. This could happen for any of the overloaded operators and functions that work with valarray, so my solution is to adjust the __fun<> class template so that the result type of valarray operations is not defined for types that cannot be used in valarray. When the result_type is missing the valarray operators give a SFINAE deduction failure not a hard error. Currently the check is !__is_abstract(_Tp) but it could be tweaked to also check other conditions that cause a problem. The new test uses -std=gnu++98 because if it uses a later standard then it fails due to similar unconstrained operators in <complex>, and std::complex<T> also fails if is_abstract<T>, so I'll have to fix that next. Tested powerpc64-linux, comimtted to trunk. This is a regression, caused by the front end starting to diagnose the invalid library instantiations more eagerly. The fix seems simple and safe, so I plan to backport it to the branches too.
commit 64f205467ab5822f4b75f9ae14933c52d5062f66 Author: Jonathan Wakely <jwak...@redhat.com> Date: Fri Jan 22 17:09:06 2016 +0000 Constrain std::valarray functions and operators PR libstdc++/69116 * include/bits/valarray_before.h (__fun, __fun_with_valarray): Only define result_type for types which can be safely used with valarrays. * testsuite/26_numerics/valarray/69116.cc: New. diff --git a/libstdc++-v3/include/bits/valarray_before.h b/libstdc++-v3/include/bits/valarray_before.h index 3325bf8..86136f4 100644 --- a/libstdc++-v3/include/bits/valarray_before.h +++ b/libstdc++-v3/include/bits/valarray_before.h @@ -331,14 +331,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return pow(__x, __y); } }; + template<typename _Tp, bool _IsValidValarrayValue = !__is_abstract(_Tp)> + struct __fun_with_valarray + { + typedef _Tp result_type; + }; + + template<typename _Tp> + struct __fun_with_valarray<_Tp, false> + { + // No result type defined for invalid value types. + }; // We need these bits in order to recover the return type of // some functions/operators now that we're no longer using // function templates. template<typename, typename _Tp> - struct __fun + struct __fun : __fun_with_valarray<_Tp> { - typedef _Tp result_type; }; // several specializations for relational operators. diff --git a/libstdc++-v3/testsuite/26_numerics/valarray/69116.cc b/libstdc++-v3/testsuite/26_numerics/valarray/69116.cc new file mode 100644 index 0000000..ef98267 --- /dev/null +++ b/libstdc++-v3/testsuite/26_numerics/valarray/69116.cc @@ -0,0 +1,53 @@ +// Copyright (C) 2016 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-do compile } +// { dg-options "-std=gnu++98" } + +// libstdc++/69116 + +#include <exception> +#include <valarray> + +template<typename T> + void foo(const T&) { } + +struct X : std::exception // makes namespace std an associated namespace +{ + virtual void pure() = 0; + + typedef void(*func_type)(const X&); + + void operator+(func_type) const; + void operator-(func_type) const; + void operator*(func_type) const; + void operator/(func_type) const; + void operator%(func_type) const; + void operator<<(func_type) const; + void operator>>(func_type) const; +}; + +void foo(X& x) +{ + x + foo; + x - foo; + x * foo; + x / foo; + x % foo; + x << foo; + x >> foo; +}