[libcxx] Fix using the vcruntime ABI with _HAS_EXCEPTIONS=0 defined
_HAS_EXCEPTIONS=0 allows disabling the exception parts of the MS STL
and vcruntime, and e.g. compiler-rt/lib/fuzzer sets this define (to
work around issues with MS STL). If using libc++ instead of MS STL,
this define previously broke the libc++ headers.
If _HAS_EXCEPTIONS is set to 0, the vcruntime_exception.h header
doesn't define the ABI base class std::exception. If no exceptions
are going to be thrown, this probably is fine (although it also
breaks using subclasses of it as regular objects that aren't thrown),
but it requires ifdeffing out all subclasses of all exception/error
derived objects (which are sprinkled throughout the headers).
Instead, libc++ will supply an ABI compatible definition when
_HAS_EXCEPTIONS is set to 0, which will make the class hierarchies
complete.
In this build configuration, one can still create instances of
exception subclasses, and those objects will be ABI incompatible
with the ones from when _HAS_EXCEPTIONS isn't defined to 0 - but
one may argue that's a pathological/self-imposed problem in that case.
Reviewed By: #libc, ldionne
Differential Revision: https://reviews.llvm.org/D103947
NOKEYCHECK=True
GitOrigin-RevId: 56a34451e1cc54375e5fd35d46c7dfba88b32fc5
diff --git a/include/exception b/include/exception
index 8294b6d..6b164e1 100644
--- a/include/exception
+++ b/include/exception
@@ -85,8 +85,10 @@
#include <type_traits>
#include <version>
+// <vcruntime_exception.h> defines its own std::exception and std::bad_exception types,
+// which we use in order to be ABI-compatible with other STLs on Windows.
#if defined(_LIBCPP_ABI_VCRUNTIME)
-#include <vcruntime_exception.h>
+# include <vcruntime_exception.h>
#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -96,24 +98,66 @@
namespace std // purposefully not using versioning namespace
{
-#if !defined(_LIBCPP_ABI_VCRUNTIME)
-class _LIBCPP_EXCEPTION_ABI exception
-{
-public:
- _LIBCPP_INLINE_VISIBILITY exception() _NOEXCEPT {}
- _LIBCPP_INLINE_VISIBILITY exception(const exception&) _NOEXCEPT = default;
+#if defined(_LIBCPP_ABI_VCRUNTIME) && (!defined(_HAS_EXCEPTIONS) || _HAS_EXCEPTIONS != 0)
+// The std::exception class was already included above, but we're explicit about this condition here for clarity.
- virtual ~exception() _NOEXCEPT;
- virtual const char* what() const _NOEXCEPT;
+#elif defined(_LIBCPP_ABI_VCRUNTIME) && _HAS_EXCEPTIONS == 0
+// However, <vcruntime_exception.h> does not define std::exception and std::bad_exception
+// when _HAS_EXCEPTIONS == 0.
+//
+// Since libc++ still wants to provide the std::exception hierarchy even when _HAS_EXCEPTIONS == 0
+// (after all those are simply types like any other), we define an ABI-compatible version
+// of the VCRuntime std::exception and std::bad_exception types in that mode.
+
+struct __std_exception_data {
+ char const* _What;
+ bool _DoFree;
};
-class _LIBCPP_EXCEPTION_ABI bad_exception
- : public exception
-{
+class exception { // base of all library exceptions
public:
- _LIBCPP_INLINE_VISIBILITY bad_exception() _NOEXCEPT {}
- virtual ~bad_exception() _NOEXCEPT;
- virtual const char* what() const _NOEXCEPT;
+ exception() _NOEXCEPT : _Data() {}
+
+ explicit exception(char const* __message) _NOEXCEPT : _Data() {
+ _Data._What = __message;
+ _Data._DoFree = true;
+ }
+
+ exception(exception const&) _NOEXCEPT {}
+
+ exception& operator=(exception const&) _NOEXCEPT { return *this; }
+
+ virtual ~exception() _NOEXCEPT {}
+
+ virtual char const* what() const _NOEXCEPT { return _Data._What ? _Data._What : "Unknown exception"; }
+
+private:
+ __std_exception_data _Data;
+};
+
+class bad_exception : public exception {
+public:
+ bad_exception() _NOEXCEPT : exception("bad exception") {}
+};
+
+#else // !defined(_LIBCPP_ABI_VCRUNTIME)
+// On all other platforms, we define our own std::exception and std::bad_exception types
+// regardless of whether exceptions are turned on as a language feature.
+
+class _LIBCPP_EXCEPTION_ABI exception {
+public:
+ _LIBCPP_INLINE_VISIBILITY exception() _NOEXCEPT {}
+ _LIBCPP_INLINE_VISIBILITY exception(const exception&) _NOEXCEPT = default;
+
+ virtual ~exception() _NOEXCEPT;
+ virtual const char* what() const _NOEXCEPT;
+};
+
+class _LIBCPP_EXCEPTION_ABI bad_exception : public exception {
+public:
+ _LIBCPP_INLINE_VISIBILITY bad_exception() _NOEXCEPT {}
+ virtual ~bad_exception() _NOEXCEPT;
+ virtual const char* what() const _NOEXCEPT;
};
#endif // !_LIBCPP_ABI_VCRUNTIME