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 Index: include/__noexcept =================================================================== --- /dev/null +++ include/__noexcept @@ -0,0 +1,40 @@ +// -*- C++ -*- +//===-------------------------- __noexcept --------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_NOEXCEPT_H +#define _LIBCPP_NOEXCEPT_H + +#include <__config> + +#ifdef _LIBCPP_NO_EXCEPTIONS +#include + +void __libcxx_noexceptions_abort(); +#endif // _LIBCPP_NO_EXCEPTIONS + +template +inline void __throw_helper(T t, const char *msg = nullptr) +{ +#ifndef _LIBCPP_NO_EXCEPTIONS + throw t; +#else + if (msg) // explicit error message provided + fprintf(stderr, "%s\n", msg); + // FIXME: instead of using the default what() string of the std::exception + // class, make all the exception classes return a meaningful error message. + else if (t.what()) + fprintf(stderr, "%s\n", t.what()); + else // use a generic error message + fprintf(stderr, "exception raised, cannot propagate. Aborting.\n"); + __libcxx_noexceptions_abort(); +#endif // _LIBCPP_NO_EXCEPTIONS +} + +#endif // _LIBCPP_NOEXCEPT_H Index: include/array =================================================================== --- include/array +++ include/array @@ -110,6 +110,7 @@ #if defined(_LIBCPP_NO_EXCEPTIONS) #include #endif +#include <__noexcept> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -201,11 +202,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 +212,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: src/noexcept.cpp =================================================================== --- /dev/null +++ src/noexcept.cpp @@ -0,0 +1,15 @@ +//===------------------------ noexcept.cpp --------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include +#include <__noexcept> + +void __libcxx_noexceptions_abort() { + abort(); +} 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,38 @@ +// -*- 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 + +#ifndef _LIBCPP_HAS_NO_THREADS +// 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! +thread_local jmp_buf try_buf; +#else +jmp_buf try_buf; +#endif + +// 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(void) { + longjmp(try_buf, 1); +} + +#endif // _LIBCPP_NO_EXCEPTIONS