Add SFINAE on additional overloads of std::complex functions. Fixes PR19921.

The functions arg, conj, imag, norm, proj, and real have additional overloads
for arguments of integral or floating point types. However these overloads should
not allow conversions to the integral/floating point types, only exact matches.

This patch constrains these functions so they no longer allow conversions.


git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@276067 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier
2016-07-20 00:14:10 +00:00
parent 99029f12eb
commit 781fb2a738
3 changed files with 137 additions and 147 deletions

View File

@@ -795,6 +795,27 @@ operator!=(const _Tp& __x, const complex<_Tp>& __y)
// 26.3.7 values: // 26.3.7 values:
template <class _Tp, bool = is_integral<_Tp>::value,
bool = is_floating_point<_Tp>::value
>
struct __libcpp_complex_overload_traits {};
// Integral Types
template <class _Tp>
struct __libcpp_complex_overload_traits<_Tp, true, false>
{
typedef double _ValueType;
typedef complex<double> _ComplexType;
};
// Floating point types
template <class _Tp>
struct __libcpp_complex_overload_traits<_Tp, false, true>
{
typedef _Tp _ValueType;
typedef complex<_Tp> _ComplexType;
};
// real // real
template<class _Tp> template<class _Tp>
@@ -805,39 +826,14 @@ real(const complex<_Tp>& __c)
return __c.real(); return __c.real();
} }
template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
long double typename __libcpp_complex_overload_traits<_Tp>::_ValueType
real(long double __re)
{
return __re;
}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
double
real(double __re)
{
return __re;
}
template<class _Tp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename enable_if
<
is_integral<_Tp>::value,
double
>::type
real(_Tp __re) real(_Tp __re)
{ {
return __re; return __re;
} }
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
float
real(float __re)
{
return __re;
}
// imag // imag
template<class _Tp> template<class _Tp>
@@ -848,39 +844,14 @@ imag(const complex<_Tp>& __c)
return __c.imag(); return __c.imag();
} }
template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
long double typename __libcpp_complex_overload_traits<_Tp>::_ValueType
imag(long double __re)
{
return 0;
}
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
double
imag(double __re)
{
return 0;
}
template<class _Tp>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
typename enable_if
<
is_integral<_Tp>::value,
double
>::type
imag(_Tp __re) imag(_Tp __re)
{ {
return 0; return 0;
} }
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
float
imag(float __re)
{
return 0;
}
// abs // abs
template<class _Tp> template<class _Tp>
@@ -901,25 +872,22 @@ arg(const complex<_Tp>& __c)
return atan2(__c.imag(), __c.real()); return atan2(__c.imag(), __c.real());
} }
template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
long double typename enable_if<
arg(long double __re) is_same<_Tp, long double>::value,
long double
>::type
arg(_Tp __re)
{ {
return atan2l(0.L, __re); return atan2l(0.L, __re);
} }
inline _LIBCPP_INLINE_VISIBILITY
double
arg(double __re)
{
return atan2(0., __re);
}
template<class _Tp> template<class _Tp>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
typename enable_if typename enable_if
< <
is_integral<_Tp>::value, is_integral<_Tp>::value || is_same<_Tp, double>::value,
double double
>::type >::type
arg(_Tp __re) arg(_Tp __re)
@@ -927,9 +895,13 @@ arg(_Tp __re)
return atan2(0., __re); return atan2(0., __re);
} }
template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
float typename enable_if<
arg(float __re) is_same<_Tp, float>::value,
float
>::type
arg(_Tp __re)
{ {
return atan2f(0.F, __re); return atan2f(0.F, __re);
} }
@@ -948,37 +920,13 @@ norm(const complex<_Tp>& __c)
return __c.real() * __c.real() + __c.imag() * __c.imag(); return __c.real() * __c.real() + __c.imag() * __c.imag();
} }
template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
long double typename __libcpp_complex_overload_traits<_Tp>::_ValueType
norm(long double __re)
{
return __re * __re;
}
inline _LIBCPP_INLINE_VISIBILITY
double
norm(double __re)
{
return __re * __re;
}
template<class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value,
double
>::type
norm(_Tp __re) norm(_Tp __re)
{ {
return (double)__re * __re; typedef typename __libcpp_complex_overload_traits<_Tp>::_ValueType _ValueType;
} return static_cast<_ValueType>(__re) * __re;
inline _LIBCPP_INLINE_VISIBILITY
float
norm(float __re)
{
return __re * __re;
} }
// conj // conj
@@ -991,38 +939,16 @@ conj(const complex<_Tp>& __c)
return complex<_Tp>(__c.real(), -__c.imag()); return complex<_Tp>(__c.real(), -__c.imag());
} }
template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
complex<long double> typename __libcpp_complex_overload_traits<_Tp>::_ComplexType
conj(long double __re)
{
return complex<long double>(__re);
}
inline _LIBCPP_INLINE_VISIBILITY
complex<double>
conj(double __re)
{
return complex<double>(__re);
}
template<class _Tp>
inline _LIBCPP_INLINE_VISIBILITY
typename enable_if
<
is_integral<_Tp>::value,
complex<double>
>::type
conj(_Tp __re) conj(_Tp __re)
{ {
return complex<double>(__re); typedef typename __libcpp_complex_overload_traits<_Tp>::_ComplexType _ComplexType;
return _ComplexType(__re);
} }
inline _LIBCPP_INLINE_VISIBILITY
complex<float>
conj(float __re)
{
return complex<float>(__re);
}
// proj // proj
@@ -1037,44 +963,33 @@ proj(const complex<_Tp>& __c)
return __r; return __r;
} }
template <class _Tp>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
complex<long double> typename enable_if
proj(long double __re) <
is_floating_point<_Tp>::value,
typename __libcpp_complex_overload_traits<_Tp>::_ComplexType
>::type
proj(_Tp __re)
{ {
if (isinf(__re)) if (isinf(__re))
__re = abs(__re); __re = abs(__re);
return complex<long double>(__re); return complex<_Tp>(__re);
} }
inline _LIBCPP_INLINE_VISIBILITY template <class _Tp>
complex<double>
proj(double __re)
{
if (isinf(__re))
__re = abs(__re);
return complex<double>(__re);
}
template<class _Tp>
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
typename enable_if typename enable_if
< <
is_integral<_Tp>::value, is_integral<_Tp>::value,
complex<double> typename __libcpp_complex_overload_traits<_Tp>::_ComplexType
>::type >::type
proj(_Tp __re) proj(_Tp __re)
{ {
return complex<double>(__re); typedef typename __libcpp_complex_overload_traits<_Tp>::_ComplexType _ComplexType;
return _ComplexType(__re);
} }
inline _LIBCPP_INLINE_VISIBILITY
complex<float>
proj(float __re)
{
if (isinf(__re))
__re = abs(__re);
return complex<float>(__re);
}
// polar // polar

View File

@@ -170,7 +170,8 @@ class LibcxxTestFormat(object):
extra_flags += ['-fsyntax-only'] extra_flags += ['-fsyntax-only']
if use_verify: if use_verify:
extra_flags += ['-Xclang', '-verify', extra_flags += ['-Xclang', '-verify',
'-Xclang', '-verify-ignore-unexpected=note'] '-Xclang', '-verify-ignore-unexpected=note',
'-ferror-limit=1024']
cmd, out, err, rc = self.cxx.compile(source_path, out=os.devnull, cmd, out, err, rc = self.cxx.compile(source_path, out=os.devnull,
flags=extra_flags, flags=extra_flags,
disable_ccache=True) disable_ccache=True)

View File

@@ -0,0 +1,74 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// <complex>
// Test that UDT's convertible to an integral or floating point type do not
// participate in overload resolution.
#include <complex>
#include <type_traits>
#include <cassert>
template <class IntT>
struct UDT {
operator IntT() const { return 1; }
};
UDT<float> ft;
UDT<double> dt;
UDT<long double> ldt;
UDT<int> it;
UDT<unsigned long> uit;
int main()
{
{
std::real(ft); // expected-error {{no matching function}}
std::real(dt); // expected-error {{no matching function}}
std::real(ldt); // expected-error {{no matching function}}
std::real(it); // expected-error {{no matching function}}
std::real(uit); // expected-error {{no matching function}}
}
{
std::imag(ft); // expected-error {{no matching function}}
std::imag(dt); // expected-error {{no matching function}}
std::imag(ldt); // expected-error {{no matching function}}
std::imag(it); // expected-error {{no matching function}}
std::imag(uit); // expected-error {{no matching function}}
}
{
std::arg(ft); // expected-error {{no matching function}}
std::arg(dt); // expected-error {{no matching function}}
std::arg(ldt); // expected-error {{no matching function}}
std::arg(it); // expected-error {{no matching function}}
std::arg(uit); // expected-error {{no matching function}}
}
{
std::norm(ft); // expected-error {{no matching function}}
std::norm(dt); // expected-error {{no matching function}}
std::norm(ldt); // expected-error {{no matching function}}
std::norm(it); // expected-error {{no matching function}}
std::norm(uit); // expected-error {{no matching function}}
}
{
std::conj(ft); // expected-error {{no matching function}}
std::conj(dt); // expected-error {{no matching function}}
std::conj(ldt); // expected-error {{no matching function}}
std::conj(it); // expected-error {{no matching function}}
std::conj(uit); // expected-error {{no matching function}}
}
{
std::proj(ft); // expected-error {{no matching function}}
std::proj(dt); // expected-error {{no matching function}}
std::proj(ldt); // expected-error {{no matching function}}
std::proj(it); // expected-error {{no matching function}}
std::proj(uit); // expected-error {{no matching function}}
}
}