[libcxx-commits] [libcxx] 317e92a - [libc++] Enable `explicit` conversion operators, even in C++03 mode.

Arthur O'Dwyer via libcxx-commits libcxx-commits at lists.llvm.org
Tue Jun 22 10:37:08 PDT 2021


Author: Arthur O'Dwyer
Date: 2021-06-22T13:35:59-04:00
New Revision: 317e92a3e82f88f111e04132195d9daa6b97f1ab

URL: https://github.com/llvm/llvm-project/commit/317e92a3e82f88f111e04132195d9daa6b97f1ab
DIFF: https://github.com/llvm/llvm-project/commit/317e92a3e82f88f111e04132195d9daa6b97f1ab.diff

LOG: [libc++] Enable `explicit` conversion operators, even in C++03 mode.

C++03 didn't support `explicit` conversion operators;
but Clang's C++03 mode does, as an extension, so we can use it.
This lets us make the conversion explicit in `std::function` (even in '03),
and remove some silly metaprogramming in `std::basic_ios`.

Drive-by improvements to the tests for these operators, in addition
to making sure all these tests also run in `c++03` mode.

Differential Revision: https://reviews.llvm.org/D104682

Added: 
    

Modified: 
    libcxx/include/__config
    libcxx/include/__functional_03
    libcxx/include/__memory/shared_ptr.h
    libcxx/include/__memory/unique_ptr.h
    libcxx/include/__mutex_base
    libcxx/include/exception
    libcxx/include/functional
    libcxx/include/ios
    libcxx/include/istream
    libcxx/include/ostream
    libcxx/include/system_error
    libcxx/test/std/diagnostics/syserr/syserr.errcode/syserr.errcode.observers/bool.pass.cpp
    libcxx/test/std/input.output/iostreams.base/ios/iostate.flags/bool.pass.cpp
    libcxx/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp
    libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.obs/op_bool.pass.cpp
    libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp
    libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.cap/operator_bool.pass.cpp
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/op_bool.pass.cpp

Removed: 
    libcxx/test/std/diagnostics/syserr/syserr.errcode/syserr.errcode.observers/bool.compile.fail.cpp


################################################################################
diff  --git a/libcxx/include/__config b/libcxx/include/__config
index abeb9a7f39ff0..a408382385541 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -874,13 +874,6 @@ typedef unsigned int   char32_t;
 #  define _LIBCPP_NOALIAS
 #endif
 
-#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
-#endif
-
 #if __has_attribute(using_if_exists)
 # define _LIBCPP_USING_IF_EXISTS __attribute__((using_if_exists))
 #else

diff  --git a/libcxx/include/__functional_03 b/libcxx/include/__functional_03
index c918fdfd1ea61..619d92e5385e0 100644
--- a/libcxx/include/__functional_03
+++ b/libcxx/include/__functional_03
@@ -493,7 +493,7 @@ public:
         {function(allocator_arg, __a, __f).swap(*this);}
 
     // 20.7.16.2.3, function capacity:
-    _LIBCPP_INLINE_VISIBILITY operator bool() const {return __f_;}
+    _LIBCPP_INLINE_VISIBILITY explicit operator bool() const {return __f_;}
 
 private:
     // deleted overloads close possible hole in the type system
@@ -773,7 +773,7 @@ public:
         {function(allocator_arg, __a, __f).swap(*this);}
 
     // 20.7.16.2.3, function capacity:
-    _LIBCPP_INLINE_VISIBILITY operator bool() const {return __f_;}
+    _LIBCPP_INLINE_VISIBILITY explicit operator bool() const {return __f_;}
 
 private:
     // deleted overloads close possible hole in the type system
@@ -1053,7 +1053,7 @@ public:
         {function(allocator_arg, __a, __f).swap(*this);}
 
     // 20.7.16.2.3, function capacity:
-    operator bool() const {return __f_;}
+    _LIBCPP_INLINE_VISIBILITY explicit operator bool() const {return __f_;}
 
 private:
     // deleted overloads close possible hole in the type system
@@ -1332,7 +1332,7 @@ public:
         {function(allocator_arg, __a, __f).swap(*this);}
 
     // 20.7.16.2.3, function capacity:
-    _LIBCPP_INLINE_VISIBILITY operator bool() const {return __f_;}
+    _LIBCPP_INLINE_VISIBILITY explicit operator bool() const {return __f_;}
 
 private:
     // deleted overloads close possible hole in the type system

diff  --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index f3253625d7086..ab92651f50d86 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -588,7 +588,7 @@ class _LIBCPP_SHARED_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS shared_ptr
     _LIBCPP_INLINE_VISIBILITY
     bool unique() const _NOEXCEPT {return use_count() == 1;}
     _LIBCPP_INLINE_VISIBILITY
-    _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT {return get() != nullptr;}
+    explicit operator bool() const _NOEXCEPT {return get() != nullptr;}
     template <class _Up>
         _LIBCPP_INLINE_VISIBILITY
         bool owner_before(shared_ptr<_Up> const& __p) const _NOEXCEPT

diff  --git a/libcxx/include/__memory/unique_ptr.h b/libcxx/include/__memory/unique_ptr.h
index 7585a918e62a0..9442e54fe98ff 100644
--- a/libcxx/include/__memory/unique_ptr.h
+++ b/libcxx/include/__memory/unique_ptr.h
@@ -296,7 +296,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr {
     return __ptr_.second();
   }
   _LIBCPP_INLINE_VISIBILITY
-  _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT {
+  explicit operator bool() const _NOEXCEPT {
     return __ptr_.first() != nullptr;
   }
 
@@ -517,7 +517,7 @@ class _LIBCPP_UNIQUE_PTR_TRIVIAL_ABI _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp>
     return __ptr_.second();
   }
   _LIBCPP_INLINE_VISIBILITY
-  _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT {
+  explicit operator bool() const _NOEXCEPT {
     return __ptr_.first() != nullptr;
   }
 

diff  --git a/libcxx/include/__mutex_base b/libcxx/include/__mutex_base
index 121973ded474a..77590a8fd4f1d 100644
--- a/libcxx/include/__mutex_base
+++ b/libcxx/include/__mutex_base
@@ -189,8 +189,7 @@ public:
     _LIBCPP_INLINE_VISIBILITY
     bool owns_lock() const _NOEXCEPT {return __owns_;}
     _LIBCPP_INLINE_VISIBILITY
-    _LIBCPP_EXPLICIT
-        operator bool () const _NOEXCEPT {return __owns_;}
+    explicit operator bool() const _NOEXCEPT {return __owns_;}
     _LIBCPP_INLINE_VISIBILITY
     mutex_type* mutex() const _NOEXCEPT {return __m_;}
 };

diff  --git a/libcxx/include/exception b/libcxx/include/exception
index 3405a4260fc6b..353ebf7441833 100644
--- a/libcxx/include/exception
+++ b/libcxx/include/exception
@@ -151,7 +151,7 @@ public:
     exception_ptr& operator=(const exception_ptr&) _NOEXCEPT;
     ~exception_ptr() _NOEXCEPT;
 
-    _LIBCPP_INLINE_VISIBILITY _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT
+    _LIBCPP_INLINE_VISIBILITY explicit operator bool() const _NOEXCEPT
     {return __ptr_ != nullptr;}
 
     friend _LIBCPP_INLINE_VISIBILITY
@@ -205,7 +205,7 @@ public:
     exception_ptr& operator=(const exception_ptr& __other) _NOEXCEPT;
     exception_ptr& operator=(nullptr_t) _NOEXCEPT;
     ~exception_ptr() _NOEXCEPT;
-    _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT;
+    explicit operator bool() const _NOEXCEPT;
 };
 
 _LIBCPP_FUNC_VIS

diff  --git a/libcxx/include/functional b/libcxx/include/functional
index 193173e02dc8e..68ed22e59cbfd 100644
--- a/libcxx/include/functional
+++ b/libcxx/include/functional
@@ -2111,7 +2111,7 @@ template <class _Rp, class... _ArgTypes> class __value_func<_Rp(_ArgTypes...)>
     }
 
     _LIBCPP_INLINE_VISIBILITY
-    _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT { return __f_ != nullptr; }
+    explicit operator bool() const _NOEXCEPT { return __f_ != nullptr; }
 
 #ifndef _LIBCPP_NO_RTTI
     _LIBCPP_INLINE_VISIBILITY
@@ -2597,7 +2597,7 @@ public:
 
     // function capacity:
     _LIBCPP_INLINE_VISIBILITY
-    _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT {
+    explicit operator bool() const _NOEXCEPT {
       return static_cast<bool>(__f_);
     }
 

diff  --git a/libcxx/include/ios b/libcxx/include/ios
index c58b98383f641..eefb58f55be13 100644
--- a/libcxx/include/ios
+++ b/libcxx/include/ios
@@ -591,13 +591,6 @@ ios_base::exceptions(iostate __iostate)
     clear(__rdstate_);
 }
 
-#if defined(_LIBCPP_CXX03_LANG)
-struct _LIBCPP_TYPE_VIS __cxx03_bool {
-  typedef void (__cxx03_bool::*__bool_type)();
-  void __true_value() {}
-};
-#endif
-
 template <class _CharT, class _Traits>
 class _LIBCPP_TEMPLATE_VIS basic_ios
     : public ios_base
@@ -614,18 +607,8 @@ public:
     static_assert((is_same<_CharT, typename traits_type::char_type>::value),
                   "traits_type::char_type must be the same type as CharT");
 
-  // __true_value will generate undefined references when linking unless
-  // we give it internal linkage.
-
-#if defined(_LIBCPP_CXX03_LANG)
     _LIBCPP_INLINE_VISIBILITY
-    operator __cxx03_bool::__bool_type() const {
-        return !fail() ? &__cxx03_bool::__true_value : nullptr;
-    }
-#else
-    _LIBCPP_INLINE_VISIBILITY
-    _LIBCPP_EXPLICIT operator bool() const {return !fail();}
-#endif
+    explicit operator bool() const {return !fail();}
 
     _LIBCPP_INLINE_VISIBILITY bool operator!() const    {return  fail();}
     _LIBCPP_INLINE_VISIBILITY iostate rdstate() const   {return ios_base::rdstate();}

diff  --git a/libcxx/include/istream b/libcxx/include/istream
index 122ea37cf65e1..7f827bbe07fb1 100644
--- a/libcxx/include/istream
+++ b/libcxx/include/istream
@@ -302,8 +302,7 @@ public:
 //    ~sentry() = default;
 
     _LIBCPP_INLINE_VISIBILITY
-        _LIBCPP_EXPLICIT
-        operator bool() const {return __ok_;}
+    explicit operator bool() const {return __ok_;}
 };
 
 template <class _CharT, class _Traits>

diff  --git a/libcxx/include/ostream b/libcxx/include/ostream
index 6a211f34b6cc9..a8faa08a18e3f 100644
--- a/libcxx/include/ostream
+++ b/libcxx/include/ostream
@@ -254,8 +254,7 @@ public:
     ~sentry();
 
     _LIBCPP_INLINE_VISIBILITY
-        _LIBCPP_EXPLICIT
-        operator bool() const {return __ok_;}
+    explicit operator bool() const {return __ok_;}
 };
 
 template <class _CharT, class _Traits>

diff  --git a/libcxx/include/system_error b/libcxx/include/system_error
index b62e2a1e770da..564f37a96b4f0 100644
--- a/libcxx/include/system_error
+++ b/libcxx/include/system_error
@@ -291,8 +291,7 @@ public:
     string message() const;
 
     _LIBCPP_INLINE_VISIBILITY
-        _LIBCPP_EXPLICIT
-        operator bool() const _NOEXCEPT {return __val_ != 0;}
+    explicit operator bool() const _NOEXCEPT {return __val_ != 0;}
 };
 
 inline _LIBCPP_INLINE_VISIBILITY
@@ -368,8 +367,7 @@ public:
     string message() const;
 
     _LIBCPP_INLINE_VISIBILITY
-        _LIBCPP_EXPLICIT
-        operator bool() const _NOEXCEPT {return __val_ != 0;}
+    explicit operator bool() const _NOEXCEPT {return __val_ != 0;}
 };
 
 inline _LIBCPP_INLINE_VISIBILITY

diff  --git a/libcxx/test/std/diagnostics/syserr/syserr.errcode/syserr.errcode.observers/bool.compile.fail.cpp b/libcxx/test/std/diagnostics/syserr/syserr.errcode/syserr.errcode.observers/bool.compile.fail.cpp
deleted file mode 100644
index 7a61c087e401a..0000000000000
--- a/libcxx/test/std/diagnostics/syserr/syserr.errcode/syserr.errcode.observers/bool.compile.fail.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// XFAIL: c++03
-
-// <system_error>
-
-// class error_code
-
-// explicit operator bool() const;
-
-#include <system_error>
-
-bool test_func(void)
-{
-    const std::error_code ec(0, std::generic_category());
-    return ec;   // conversion to bool is explicit; should fail.
-}
-
-int main(int, char**)
-{
-    return 0;
-}

diff  --git a/libcxx/test/std/diagnostics/syserr/syserr.errcode/syserr.errcode.observers/bool.pass.cpp b/libcxx/test/std/diagnostics/syserr/syserr.errcode/syserr.errcode.observers/bool.pass.cpp
index a67ddb397f24c..2e140964b26c2 100644
--- a/libcxx/test/std/diagnostics/syserr/syserr.errcode/syserr.errcode.observers/bool.pass.cpp
+++ b/libcxx/test/std/diagnostics/syserr/syserr.errcode/syserr.errcode.observers/bool.pass.cpp
@@ -13,13 +13,17 @@
 // explicit operator bool() const;
 
 #include <system_error>
-#include <string>
 #include <cassert>
+#include <string>
+#include <type_traits>
 
 #include "test_macros.h"
 
 int main(int, char**)
 {
+    static_assert(std::is_constructible<bool, std::error_code>::value, "");
+    static_assert(!std::is_convertible<std::error_code, bool>::value, "");
+
     {
         const std::error_code ec(6, std::generic_category());
         assert(static_cast<bool>(ec));

diff  --git a/libcxx/test/std/input.output/iostreams.base/ios/iostate.flags/bool.pass.cpp b/libcxx/test/std/input.output/iostreams.base/ios/iostate.flags/bool.pass.cpp
index 24fcbff39260c..59896c82f29b9 100644
--- a/libcxx/test/std/input.output/iostreams.base/ios/iostate.flags/bool.pass.cpp
+++ b/libcxx/test/std/input.output/iostreams.base/ios/iostate.flags/bool.pass.cpp
@@ -27,9 +27,7 @@ int main(int, char**)
     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
 
   return 0;
 }

diff  --git a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp
index 5bd11903a6085..0aded33e660d5 100644
--- a/libcxx/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp
+++ b/libcxx/test/std/language.support/support.exception/propagation/exception_ptr.pass.cpp
@@ -14,6 +14,7 @@
 
 #include <exception>
 #include <cassert>
+#include <type_traits>
 
 #include "test_macros.h"
 
@@ -33,5 +34,5 @@ int main(int, char**)
     p3 = nullptr;
     assert(p3 == nullptr);
 
-  return 0;
+    return 0;
 }

diff  --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.obs/op_bool.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.obs/op_bool.pass.cpp
index ac6499fbc2075..ecc47b888247b 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.obs/op_bool.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.shared/thread.lock.shared.obs/op_bool.pass.cpp
@@ -9,11 +9,6 @@
 // UNSUPPORTED: libcpp-has-no-threads
 // UNSUPPORTED: c++03, c++11
 
-// dylib support for shared_mutex was added in macosx10.12
-// XFAIL: use_system_cxx_lib && x86_64-apple-macosx10.11
-// XFAIL: use_system_cxx_lib && x86_64-apple-macosx10.10
-// XFAIL: use_system_cxx_lib && x86_64-apple-macosx10.9
-
 // <shared_mutex>
 
 // template <class Mutex> class shared_lock;
@@ -25,17 +20,24 @@
 
 #include "test_macros.h"
 
-std::shared_timed_mutex m;
+struct M {
+    void lock_shared() {}
+    void unlock_shared() {}
+};
 
 int main(int, char**)
 {
-    std::shared_lock<std::shared_timed_mutex> lk0;
+    static_assert(std::is_constructible<bool, std::shared_lock<M>>::value, "");
+    static_assert(!std::is_convertible<std::shared_lock<M>, bool>::value, "");
+
+    M m;
+    std::shared_lock<M> lk0;
     assert(static_cast<bool>(lk0) == false);
-    std::shared_lock<std::shared_timed_mutex> lk1(m);
+    std::shared_lock<M> lk1(m);
     assert(static_cast<bool>(lk1) == true);
     lk1.unlock();
     assert(static_cast<bool>(lk1) == false);
-    static_assert(noexcept(static_cast<bool>(lk0)), "explicit operator bool() must be noexcept");
+    ASSERT_NOEXCEPT(static_cast<bool>(lk0));
 
-  return 0;
+    return 0;
 }

diff  --git a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp
index 681fc4ba5d799..5304f79485f9f 100644
--- a/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp
+++ b/libcxx/test/std/thread/thread.mutex/thread.lock/thread.lock.unique/thread.lock.unique.obs/op_bool.pass.cpp
@@ -12,10 +12,11 @@
 
 // template <class Mutex> class unique_lock;
 
-// explicit operator bool() const;
+// explicit operator bool() const noexcept;
 
 #include <mutex>
 #include <cassert>
+#include <type_traits>
 
 #include "test_macros.h"
 
@@ -23,12 +24,16 @@ std::mutex m;
 
 int main(int, char**)
 {
+    static_assert(std::is_constructible<bool, std::unique_lock<std::mutex> >::value, "");
+    static_assert(!std::is_convertible<std::unique_lock<std::mutex>, bool>::value, "");
+
     std::unique_lock<std::mutex> lk0;
     assert(static_cast<bool>(lk0) == false);
     std::unique_lock<std::mutex> lk1(m);
     assert(static_cast<bool>(lk1) == true);
     lk1.unlock();
     assert(static_cast<bool>(lk1) == false);
+    ASSERT_NOEXCEPT(static_cast<bool>(lk0));
 
   return 0;
 }

diff  --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.cap/operator_bool.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.cap/operator_bool.pass.cpp
index fbfc658f2de67..165f1a92007ba 100644
--- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.cap/operator_bool.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.cap/operator_bool.pass.cpp
@@ -17,6 +17,7 @@
 
 #include <functional>
 #include <cassert>
+#include <type_traits>
 
 #include "test_macros.h"
 
@@ -24,6 +25,9 @@ int g(int) {return 0;}
 
 int main(int, char**)
 {
+    static_assert(std::is_constructible<bool, std::function<void()> >::value, "");
+    static_assert(!std::is_convertible<std::function<void()>, bool>::value, "");
+
     {
     std::function<int(int)> f;
     assert(!f);

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/op_bool.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/op_bool.pass.cpp
index bf6d495c34fff..d8c067c7be8e7 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/op_bool.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.obs/op_bool.pass.cpp
@@ -14,6 +14,7 @@
 
 #include <memory>
 #include <cassert>
+#include <type_traits>
 
 #include "test_macros.h"
 
@@ -25,6 +26,9 @@ struct B : A {};
 
 int main(int, char**)
 {
+    static_assert(std::is_constructible<bool, std::shared_ptr<A> >::value, "");
+    static_assert(!std::is_convertible<std::shared_ptr<A>, bool>::value, "");
+
     {
       const std::shared_ptr<int> p(new int(32));
       assert(p);


        


More information about the libcxx-commits mailing list