Add SFINAE on additional overloads of std::complex functions. Fixes PR19921.
authorEric Fiselier <eric@efcs.ca>
Wed, 20 Jul 2016 00:14:10 +0000 (00:14 +0000)
committerEric Fiselier <eric@efcs.ca>
Wed, 20 Jul 2016 00:14:10 +0000 (00:14 +0000)
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.

llvm-svn: 276067

libcxx/include/complex
libcxx/test/libcxx/test/format.py
libcxx/test/std/numerics/complex.number/cmplx.over/UDT_is_rejected.fail.cpp [new file with mode: 0644]

index f56138f..d20a30c 100644 (file)
@@ -795,45 +795,41 @@ operator!=(const _Tp& __x, const complex<_Tp>& __y)
 
 // 26.3.7 values:
 
-// real
+template <class _Tp, bool = is_integral<_Tp>::value,
+                     bool = is_floating_point<_Tp>::value
+                     >
+struct __libcpp_complex_overload_traits {};
 
-template<class _Tp>
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-_Tp
-real(const complex<_Tp>& __c)
+// Integral Types
+template <class _Tp>
+struct __libcpp_complex_overload_traits<_Tp, true, false>
 {
-    return __c.real();
-}
+    typedef double _ValueType;
+    typedef complex<double> _ComplexType;
+};
 
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-long double
-real(long double __re)
+// Floating point types
+template <class _Tp>
+struct __libcpp_complex_overload_traits<_Tp, false, true>
 {
-    return __re;
-}
+    typedef _Tp _ValueType;
+    typedef complex<_Tp> _ComplexType;
+};
 
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-double
-real(double __re)
-{
-    return __re;
-}
+// real
 
 template<class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-typename enable_if
-<
-    is_integral<_Tp>::value,
-    double
->::type
-real(_Tp  __re)
+_Tp
+real(const complex<_Tp>& __c)
 {
-    return __re;
+    return __c.real();
 }
 
+template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-float
-real(float  __re)
+typename __libcpp_complex_overload_traits<_Tp>::_ValueType
+real(_Tp __re)
 {
     return __re;
 }
@@ -848,35 +844,10 @@ imag(const complex<_Tp>& __c)
     return __c.imag();
 }
 
+template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-long double
-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)
-{
-    return 0;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-float
-imag(float  __re)
+typename __libcpp_complex_overload_traits<_Tp>::_ValueType
+imag(_Tp __re)
 {
     return 0;
 }
@@ -901,25 +872,22 @@ arg(const complex<_Tp>& __c)
     return atan2(__c.imag(), __c.real());
 }
 
+template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
-long double
-arg(long double __re)
+typename enable_if<
+    is_same<_Tp, long double>::value,
+    long double
+>::type
+arg(_Tp __re)
 {
     return atan2l(0.L, __re);
 }
 
-inline _LIBCPP_INLINE_VISIBILITY
-double
-arg(double __re)
-{
-    return atan2(0., __re);
-}
-
 template<class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
 typename enable_if
 <
-    is_integral<_Tp>::value,
+    is_integral<_Tp>::value || is_same<_Tp, double>::value,
     double
 >::type
 arg(_Tp __re)
@@ -927,9 +895,13 @@ arg(_Tp __re)
     return atan2(0., __re);
 }
 
+template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
-float
-arg(float __re)
+typename enable_if<
+    is_same<_Tp, float>::value,
+    float
+>::type
+arg(_Tp __re)
 {
     return atan2f(0.F, __re);
 }
@@ -948,37 +920,13 @@ norm(const complex<_Tp>& __c)
     return __c.real() * __c.real() + __c.imag() * __c.imag();
 }
 
+template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
-long double
-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
+typename __libcpp_complex_overload_traits<_Tp>::_ValueType
 norm(_Tp __re)
 {
-    return (double)__re * __re;
-}
-
-inline _LIBCPP_INLINE_VISIBILITY
-float
-norm(float __re)
-{
-    return __re * __re;
+    typedef typename __libcpp_complex_overload_traits<_Tp>::_ValueType _ValueType;
+    return static_cast<_ValueType>(__re) * __re;
 }
 
 // conj
@@ -991,38 +939,16 @@ conj(const complex<_Tp>& __c)
     return complex<_Tp>(__c.real(), -__c.imag());
 }
 
+template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
-complex<long double>
-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
+typename __libcpp_complex_overload_traits<_Tp>::_ComplexType
 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
 
@@ -1037,44 +963,33 @@ proj(const complex<_Tp>& __c)
     return __r;
 }
 
+template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
-complex<long double>
-proj(long double __re)
-{
-    if (isinf(__re))
-        __re = abs(__re);
-    return complex<long double>(__re);
-}
-
-inline _LIBCPP_INLINE_VISIBILITY
-complex<double>
-proj(double __re)
+typename enable_if
+<
+    is_floating_point<_Tp>::value,
+    typename __libcpp_complex_overload_traits<_Tp>::_ComplexType
+>::type
+proj(_Tp __re)
 {
     if (isinf(__re))
         __re = abs(__re);
-    return complex<double>(__re);
+    return complex<_Tp>(__re);
 }
 
-template<class _Tp>
+template <class _Tp>
 inline _LIBCPP_INLINE_VISIBILITY
 typename enable_if
 <
     is_integral<_Tp>::value,
-    complex<double>
+    typename __libcpp_complex_overload_traits<_Tp>::_ComplexType
 >::type
 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
 
index b9ec2ba..66553bd 100644 (file)
@@ -170,7 +170,8 @@ class LibcxxTestFormat(object):
             extra_flags += ['-fsyntax-only']
         if use_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,
                                              flags=extra_flags,
                                              disable_ccache=True)
diff --git a/libcxx/test/std/numerics/complex.number/cmplx.over/UDT_is_rejected.fail.cpp b/libcxx/test/std/numerics/complex.number/cmplx.over/UDT_is_rejected.fail.cpp
new file mode 100644 (file)
index 0000000..6a3ae48
--- /dev/null
@@ -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}}
+    }
+}