#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)
namespace std // purposefully not using versioning namespace
{
-#if !defined(_LIBCPP_ABI_VCRUNTIME)
-class _LIBCPP_EXCEPTION_ABI exception
-{
+#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.
+
+#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 exception { // base of all library exceptions
public:
- _LIBCPP_INLINE_VISIBILITY exception() _NOEXCEPT {}
- _LIBCPP_INLINE_VISIBILITY exception(const exception&) _NOEXCEPT = default;
+ 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"; }
- virtual ~exception() _NOEXCEPT;
- virtual const char* what() const _NOEXCEPT;
+private:
+ __std_exception_data _Data;
};
-class _LIBCPP_EXCEPTION_ABI bad_exception
- : public exception
-{
+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;
+ _LIBCPP_INLINE_VISIBILITY bad_exception() _NOEXCEPT {}
+ virtual ~bad_exception() _NOEXCEPT;
+ virtual const char* what() const _NOEXCEPT;
};
#endif // !_LIBCPP_ABI_VCRUNTIME
_LIBCPP_FUNC_VIS new_handler set_new_handler(new_handler) _NOEXCEPT;
_LIBCPP_FUNC_VIS new_handler get_new_handler() _NOEXCEPT;
-#endif // !_LIBCPP_ABI_VCRUNTIME
+#elif defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS == 0 // !_LIBCPP_ABI_VCRUNTIME
+
+// When _HAS_EXCEPTIONS == 0, these complete definitions are needed,
+// since they would normally be provided in vcruntime_exception.h
+class bad_alloc : public exception {
+public:
+ bad_alloc() noexcept : exception("bad allocation") {}
+
+private:
+ friend class bad_array_new_length;
+
+ bad_alloc(char const* const __message) noexcept : exception(__message) {}
+};
+
+class bad_array_new_length : public bad_alloc {
+public:
+ bad_array_new_length() noexcept : bad_alloc("bad array new length") {}
+};
+#endif // defined(_LIBCPP_ABI_VCRUNTIME) && defined(_HAS_EXCEPTIONS) &&_HAS_EXCEPTIONS == 0
_LIBCPP_NORETURN _LIBCPP_FUNC_VIS void __throw_bad_alloc(); // not in C++ spec
#endif // defined(_LIBCPP_ABI_VCRUNTIME)
+#if defined(_LIBCPP_ABI_VCRUNTIME) && _HAS_EXCEPTIONS == 0
+
+namespace std {
+
+class bad_cast : public exception {
+public:
+ bad_cast() _NOEXCEPT : exception("bad cast") {}
+
+private:
+ bad_cast(const char* const __message) _NOEXCEPT : exception(__message) {}
+};
+
+class bad_typeid : public exception {
+public:
+ bad_typeid() _NOEXCEPT : exception("bad typeid") {}
+
+private:
+ bad_typeid(const char* const __message) _NOEXCEPT : exception(__message) {}
+};
+
+} // namespace std
+
+#endif // defined(_LIBCPP_ABI_VCRUNTIME) && _HAS_EXCEPTIONS == 0
+
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_NORETURN inline _LIBCPP_INLINE_VISIBILITY
void __throw_bad_cast()
--- /dev/null
+# This testing configuration handles running the test suite against LLVM's libc++
+# using a DLL, with Clang-cl on Windows. This variant sets _HAS_EXCEPTIONS = 0
+# which removes exception class definitions from the vcruntime.
+
+lit_config.load_config(config, '@CMAKE_CURRENT_BINARY_DIR@/cmake-bridge.cfg')
+
+config.substitutions.append(('%{flags}', '--driver-mode=g++'))
+config.substitutions.append(('%{compile_flags}',
+ '-nostdinc++ -I %{include} -I %{target-include} -I %{libcxx}/test/support -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_CRT_STDIO_ISO_WIDE_SPECIFIERS -DNOMINMAX -D_HAS_EXCEPTIONS=0'
+))
+config.substitutions.append(('%{link_flags}',
+ '-nostdlib -L %{lib} -lc++ -lmsvcrt -lmsvcprt -loldnames'
+))
+config.substitutions.append(('%{exec}',
+ '%{executor} --execdir %T --env PATH=%{lib} -- '
+))
+
+import os, site
+site.addsitedir(os.path.join('@LIBCXX_SOURCE_DIR@', 'utils'))
+import libcxx.test.params, libcxx.test.newconfig
+libcxx.test.newconfig.configure(
+ libcxx.test.params.DEFAULT_PARAMETERS,
+ libcxx.test.features.DEFAULT_FEATURES,
+ config,
+ lit_config
+)
limit: 2
timeout_in_minutes: 120
+ - label: "Clang-cl (no vcruntime exceptions)"
+ command: "bash libcxx/utils/ci/run-buildbot clang-cl-no-vcruntime"
+ artifact_paths:
+ - "**/test-results.xml"
+ - "**/*.abilist"
+ agents:
+ queue: "windows"
+ retry:
+ automatic:
+ - exit_status: -1 # Agent was lost
+ limit: 2
+
- label: "MinGW (DLL, x86_64)"
command: "bash libcxx/utils/ci/run-buildbot mingw-dll"
artifact_paths:
echo "+++ Running the libc++ tests"
${NINJA} -vC "${BUILD_DIR}" check-cxx
;;
+clang-cl-no-vcruntime)
+ clean
+ # Building libc++ in the same way as in clang-cl-dll above, but running
+ # tests with -D_HAS_EXCEPTIONS=0, which users might set in certain
+ # translation units while using libc++, even if libc++ is built with
+ # exceptions enabled.
+ generate-cmake-libcxx-win -DLIBCXX_TEST_PARAMS="enable_experimental=False" \
+ -DLIBCXX_TEST_CONFIG="llvm-libc++-shared-no-vcruntime-clangcl.cfg.in"
+ echo "+++ Running the libc++ tests"
+ ${NINJA} -vC "${BUILD_DIR}" check-cxx
+;;
mingw-dll)
clean
# Explicitly specify the compiler with a triple prefix. The CI