[libcxx] r290754 - Recommit r290750: Fix PR19460 - std::ios is convertible to int.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 30 06:05:53 PST 2016


Author: ericwf
Date: Fri Dec 30 08:05:52 2016
New Revision: 290754

URL: http://llvm.org/viewvc/llvm-project?rev=290754&view=rev
Log:
Recommit r290750: Fix PR19460 - std::ios is convertible to int.

There were two problems with the initial fix.

1. The added tests flushed out that we misconfigured _LIBCPP_EXPLICIT with GCC.

2. Because the boolean type was a member function template it caused weird link
   errors. I'm assuming due to the vague linkage rules. This time the bool type
   is a non-template member function pointer. That seems to have fixed the
   failing tests. Plus it will end up generating less symbols overall, since
   the bool type is no longer per instantiation.

original commit message below
-----------------------------

std::basic_ios has an operator bool(). In C++11 and later
it is explicit, and only allows contextual implicit conversions.

However explicit isn't available in C++03 which causes std::istream (et al)
to have an implicit conversion to int. This can easily cause ambiguities
when calling operator<< and operator>>.

This patch uses a "bool-like" type in C++03 to work around this. The
"bool-like" type is an arbitrary pointer to member function type. It
will not convert to either int or void*, but will convert to bool.

Modified:
    libcxx/trunk/include/__config
    libcxx/trunk/include/ios
    libcxx/trunk/test/std/input.output/iostreams.base/ios/iostate.flags/bool.pass.cpp

Modified: libcxx/trunk/include/__config
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__config?rev=290754&r1=290753&r2=290754&view=diff
==============================================================================
--- libcxx/trunk/include/__config (original)
+++ libcxx/trunk/include/__config Fri Dec 30 08:05:52 2016
@@ -727,7 +727,8 @@ template <unsigned> struct __static_asse
 #define _NOALIAS
 #endif
 
-#if __has_feature(cxx_explicit_conversions) || defined(__IBMCPP__)
+#if __has_feature(cxx_explicit_conversions) || defined(__IBMCPP__) || \
+    (!defined(_LIBCPP_CXX03_LANG) && defined(__GNUC__)) // All supported GCC versions
 #   define _LIBCPP_EXPLICIT explicit
 #else
 #   define _LIBCPP_EXPLICIT

Modified: libcxx/trunk/include/ios
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/ios?rev=290754&r1=290753&r2=290754&view=diff
==============================================================================
--- libcxx/trunk/include/ios (original)
+++ libcxx/trunk/include/ios Fri Dec 30 08:05:52 2016
@@ -572,6 +572,13 @@ ios_base::exceptions(iostate __iostate)
     clear(__rdstate_);
 }
 
+#if defined(_LIBCPP_CXX03_LANG)
+struct _LIBCPP_TYPE_VIS_ONLY __cxx03_bool {
+  typedef void (__cxx03_bool::*__bool_type)();
+  void __true_value() {}
+};
+#endif
+
 template <class _CharT, class _Traits>
 class _LIBCPP_TYPE_VIS_ONLY basic_ios
     : public ios_base
@@ -585,9 +592,19 @@ public:
     typedef typename traits_type::pos_type pos_type;
     typedef typename traits_type::off_type off_type;
 
+  // __true_value will generate undefined references when linking unless
+  // we give it internal linkage.
+
+#if defined(_LIBCPP_CXX03_LANG)
     _LIBCPP_ALWAYS_INLINE
-        _LIBCPP_EXPLICIT
-        operator bool() const {return !fail();}
+    operator __cxx03_bool::__bool_type() const {
+        return !fail() ? &__cxx03_bool::__true_value : nullptr;
+    }
+#else
+    _LIBCPP_ALWAYS_INLINE
+    _LIBCPP_EXPLICIT operator bool() const {return !fail();}
+#endif
+
     _LIBCPP_ALWAYS_INLINE bool operator!() const    {return  fail();}
     _LIBCPP_ALWAYS_INLINE iostate rdstate() const   {return ios_base::rdstate();}
     _LIBCPP_ALWAYS_INLINE void clear(iostate __state = goodbit) {ios_base::clear(__state);}

Modified: libcxx/trunk/test/std/input.output/iostreams.base/ios/iostate.flags/bool.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/input.output/iostreams.base/ios/iostate.flags/bool.pass.cpp?rev=290754&r1=290753&r2=290754&view=diff
==============================================================================
--- libcxx/trunk/test/std/input.output/iostreams.base/ios/iostate.flags/bool.pass.cpp (original)
+++ libcxx/trunk/test/std/input.output/iostreams.base/ios/iostate.flags/bool.pass.cpp Fri Dec 30 08:05:52 2016
@@ -14,12 +14,21 @@
 // operator unspecified-bool-type() const;
 
 #include <ios>
+#include <type_traits>
 #include <cassert>
 
+#include "test_macros.h"
+
 int main()
 {
     std::ios ios(0);
     assert(static_cast<bool>(ios) == !ios.fail());
     ios.setstate(std::ios::failbit);
     assert(static_cast<bool>(ios) == !ios.fail());
+    static_assert((!std::is_convertible<std::ios, void*>::value), "");
+    static_assert((!std::is_convertible<std::ios, int>::value), "");
+    static_assert((!std::is_convertible<std::ios const&, int>::value), "");
+#if TEST_STD_VER >= 11
+    static_assert((!std::is_convertible<std::ios, bool>::value), "");
+#endif
 }




More information about the cfe-commits mailing list