rmaprath updated this revision to Diff 43237.
rmaprath added a comment.

Addressing review comments by @mclow.lists:
- Introduced `TEST_TRY` and `TEST_CATCH` macros to avoid the non-standard 
`#define try/catch`.


http://reviews.llvm.org/D14653

Files:
  include/__config
  include/array
  test/std/containers/sequences/array/at.pass.cpp
  test/support/noexcept.h
  test/support/test_allocator.h

Index: test/support/test_allocator.h
===================================================================
--- test/support/test_allocator.h
+++ test/support/test_allocator.h
@@ -65,13 +65,8 @@
     pointer allocate(size_type n, const void* = 0)
         {
             assert(data_ >= 0);
-            if (time_to_throw >= throw_after) {
-#ifndef _LIBCPP_NO_EXCEPTIONS
-                throw std::bad_alloc();
-#else
-                std::terminate();
-#endif
-            }
+            if (time_to_throw >= throw_after)
+                _LIBCPP_THROW(std::bad_alloc(), "std::bad_alloc");
             ++time_to_throw;
             ++alloc_count;
             return (pointer)::operator new(n * sizeof(T));
@@ -125,13 +120,8 @@
     pointer allocate(size_type n, const void* = 0)
         {
             assert(data_ >= 0);
-            if (time_to_throw >= throw_after) {
-#ifndef _LIBCPP_NO_EXCEPTIONS
-                throw std::bad_alloc();
-#else
-                std::terminate();
-#endif
-            }
+            if (time_to_throw >= throw_after)
+                _LIBCPP_THROW(std::bad_alloc(), "std::bad_alloc");
             ++time_to_throw;
             ++alloc_count;
             return (pointer)::operator new (n * sizeof(T));
Index: test/support/noexcept.h
===================================================================
--- /dev/null
+++ test/support/noexcept.h
@@ -0,0 +1,61 @@
+// -*- 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.
+//
+//===----------------------------------------------------------------------===//
+#ifndef NOEXCEPT_H
+#define NOEXCEPT_H
+
+// These helper macros enable writing tests for the standard library exceptions
+// (i.e. tests that check the library throws where it should) while at the same
+// time catering for the no-exceptions library variant. In the no-exceptions
+// variant, the macros translate into a setjmp/longjmp duo that mimic the
+// control flow of exceptions. The goal here is to allow the tests to verify
+// that the library called __libcxx_noexceptions_abort() at the point where it
+// originally threw. Note that the longjmp (and hence the setjmp) is necessary
+// here as we cannot allow the execution to proceed past the point where the
+// library detects an error. Finally, this simple translation does not work when
+// tests use multiple catch statements, in those cases we have to use the
+// _LIBCPP_NO_EXCEPTIONS macro and exclude the additional catch statements.
+#ifndef _LIBCPP_NO_EXCEPTIONS
+#define TEST_TRY try
+#define TEST_CATCH(E) catch (E)
+#define TEST_THROW(E) throw E
+#else
+#define TEST_TRY if (!setjmp(try_buf))
+#define TEST_CATCH(E) else
+#define TEST_THROW(E) __libcxx_noexceptions_abort("exception")
+
+#include <setjmp.h>
+#include <cstdio>
+#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
+
+void __libcxx_noexceptions_abort(const char *msg) {
+  fprintf(stderr, "%s\n", msg);
+  longjmp(try_buf, 1);
+}
+#endif // _LIBCPP_NO_EXCEPTIONS
+
+#endif // NOEXCEPT_H
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
 // <array>
 
 // reference operator[] (size_type)
@@ -19,6 +18,7 @@
 #include <cassert>
 
 #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.
@@ -40,8 +40,8 @@
         r2 = 7.5;
         assert(c.back() == 7.5);
 
-        try { (void) c.at(3); }
-        catch (const std::out_of_range &) {}
+        TEST_TRY { (void) c.at(3); }
+        TEST_CATCH (const std::out_of_range &) {}
     }
     {
         typedef double T;
@@ -53,8 +53,8 @@
         C::const_reference r2 = c.at(2);
         assert(r2 == 3.5);
 
-        try { (void) c.at(3); }
-        catch (const std::out_of_range &) {}
+        TEST_TRY { (void) c.at(3); }
+        TEST_CATCH (const std::out_of_range &) {}
     }
     
 #if TEST_STD_VER > 11
Index: include/array
===================================================================
--- include/array
+++ include/array
@@ -201,11 +201,8 @@
 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
+        _LIBCPP_THROW(out_of_range("array::at out_of_range"),
+                      "array::at out_of_range");
     return __elems_[__n];
 }
 
@@ -215,11 +212,8 @@
 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
+        _LIBCPP_THROW(out_of_range("array::at out_of_range"),
+                      "array::at out_of_range");
     return __elems_[__n];
 }
 
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,20 @@
 #define _LIBCPP_HAS_NO_ATOMIC_HEADER
 #endif
 
+#ifdef _LIBCPP_NO_EXCEPTIONS
+_LIBCPP_NORETURN _LIBCPP_WEAK void __libcxx_noexceptions_abort(const char *msg);
+extern "C++" {
+inline void __libcxx_noexceptions_report(const char *msg = nullptr)
+{
+    if (__libcxx_noexceptions_abort)
+        __libcxx_noexceptions_abort(msg);
+}
+}
+#define _LIBCPP_THROW(E, MSG) __libcxx_noexceptions_report(MSG)
+#else  // !_LIBCPP_NO_EXCEPTIONS
+#define _LIBCPP_THROW(E, MSG) throw E
+#endif // _LIBCPP_NO_EXCEPTIONS
+
 #endif // __cplusplus
 
 #endif // _LIBCPP_CONFIG
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to