Index: include/__config =================================================================== --- include/__config +++ include/__config @@ -281,7 +281,7 @@ typedef __char32_t char32_t; #endif -#if !(__has_feature(cxx_exceptions)) +#if !(__has_feature(cxx_exceptions)) && !defined(_LIBCPP_NO_EXCEPTIONS) #define _LIBCPP_NO_EXCEPTIONS #endif @@ -825,6 +825,29 @@ #define _LIBCPP_HAS_NO_ATOMIC_HEADER #endif +#ifdef _LIBCPP_NO_EXCEPTIONS +void _LIBCPP_WEAK __libcxx_noexceptions_abort(const char *msg); +#endif // _LIBCPP_NO_EXCEPTIONS + +extern "C++" { +template +inline void __throw_helper(T t, const char *msg = nullptr) +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + throw t; +#else + if (__libcxx_noexceptions_abort) { + if (msg) + __libcxx_noexceptions_abort(msg); + else if (t.what()) + __libcxx_noexceptions_abort(t.what()); + else + __libcxx_noexceptions_abort("Exception raised, cannot propagate.\n"); + } +#endif // _LIBCPP_NO_EXCEPTIONS +} +} + #endif // __cplusplus #endif // _LIBCPP_CONFIG Index: include/array =================================================================== --- include/array +++ include/array @@ -201,11 +201,7 @@ array<_Tp, _Size>::at(size_type __n) { if (__n >= _Size) -#ifndef _LIBCPP_NO_EXCEPTIONS - throw out_of_range("array::at"); -#else - assert(!"array::at out_of_range"); -#endif + __throw_helper(out_of_range("array::at out_of_range")); return __elems_[__n]; } @@ -215,11 +211,7 @@ array<_Tp, _Size>::at(size_type __n) const { if (__n >= _Size) -#ifndef _LIBCPP_NO_EXCEPTIONS - throw out_of_range("array::at"); -#else - assert(!"array::at out_of_range"); -#endif + __throw_helper(out_of_range("array::at out_of_range")); return __elems_[__n]; } Index: test/std/containers/sequences/array/at.pass.cpp =================================================================== --- test/std/containers/sequences/array/at.pass.cpp +++ test/std/containers/sequences/array/at.pass.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// -// XFAIL: libcpp-no-exceptions // // reference operator[] (size_type) @@ -19,6 +18,7 @@ #include #include "test_macros.h" +#include "noexcept.h" // std::array is explicitly allowed to be initialized with A a = { init-list };. // Disable the missing braces warning for this reason. Index: test/support/noexcept.h =================================================================== --- /dev/null +++ test/support/noexcept.h @@ -0,0 +1,48 @@ +// -*- C++ -*- +//===----------------------------- noexcept.h -----------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// +#ifdef _LIBCPP_NO_EXCEPTIONS + +#include +#include +#include "test_macros.h" + +#ifndef _LIBCPP_HAS_NO_THREADS +# if TEST_STD_VER >= 11 +# define TLS_SPEC thread_local +# elif defined(_LIBCPP_MSVC) +# define TLS_SPEC __declspec(thread) +# else +# define TLS_SPEC __thread +# endif +#else +# define TLS_SPEC +#endif + +// Some tests launch multiple threads, in which case we need to make sure that +// try_buf is maintained per-thread, otherwise setjmp()/longjmp() will attempt +// to jump between threads! +TLS_SPEC jmp_buf try_buf; +#undef TLS_SPEC + +// Re-write try/catch with if/else to mimic a similar control flow when testing +// the no-exceptions library variant. The idea is to save as much of the usual +// with-exceptions assertions as possible. This of course does not work when +// there are multiple catch statements, in those cases we have to use the +// _LIBCPP_NO_EXCEPTIONS macro as appropriate; such cases are rare. +#define try if(!setjmp(try_buf)) +#define catch(ex) else + +// Jump back to the catch (now else) clause. +void __libcxx_noexceptions_abort(const char *msg) { + fprintf(stderr, "%s\n", msg); + longjmp(try_buf, 1); +} + +#endif // _LIBCPP_NO_EXCEPTIONS