third_party/libcxxabi: Add test suite (#1076)

Added the `libcxxabi` test suite as found in LLVM 17.0.6.

Some tests that do not apply to the current configuration of
comsopolitan are not added. These include:
- `backtrace_test`, `forced_unwind*`: Use unwind function unsupported in
SjLj mode.
- `noexception*`: Designed to test `libcxxabi` in no exceptions mode.

Some tests are added but not enabled due to bugs specific to GCC or
cosmopolitan. These are clearly indicated in the `BUILD.mk` file.
This commit is contained in:
Trung Nguyen 2024-01-09 01:50:06 +07:00 committed by GitHub
parent 8fb24a8f88
commit b0566348b2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
65 changed files with 43262 additions and 2 deletions

View file

@ -330,6 +330,7 @@ include third_party/python/BUILD.mk
include tool/build/BUILD.mk
include tool/curl/BUILD.mk
include third_party/qemu/BUILD.mk
include third_party/libcxxabi/test/BUILD.mk
include examples/BUILD.mk
include examples/pyapp/BUILD.mk
include examples/pylife/BUILD.mk

View file

@ -107,6 +107,7 @@ THIRD_PARTY_LIBCXXABI_CHECKS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$(
THIRD_PARTY_LIBCXXABI_OBJS = $(foreach x,$(THIRD_PARTY_LIBCXXABI_ARTIFACTS),$($(x)_OBJS))
.PHONY: o/$(MODE)/third_party/libcxxabi
o/$(MODE)/third_party/libcxxabi: \
$(THIRD_PARTY_LIBCXXABI_CHECKS) \
o/$(MODE)/third_party/libcxxabi: \
o/$(MODE)/third_party/libcxxabi/test \
$(THIRD_PARTY_LIBCXXABI_CHECKS) \
$(THIRD_PARTY_LIBCXXABI_A)

View file

@ -15,4 +15,6 @@ LOCAL CHANGES
- Add <__memory/aligned_alloc.h> (contains a few inline functions) from
upstream libcxx.
- Add <test/support/make_test_thread.hh> and <test/support/test_macros.hh>
from upstream libcxx.
- Enable __cxa_thread_atexit for Cosmopolitan.

View file

@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef TEST_SUPPORT_MAKE_TEST_THREAD_H
#define TEST_SUPPORT_MAKE_TEST_THREAD_H
#include <thread>
#include <utility>
namespace support {
template <class F, class ...Args>
std::thread make_test_thread(F&& f, Args&& ...args) {
return std::thread(std::forward<F>(f), std::forward<Args>(args)...);
}
} // end namespace support
#endif // TEST_SUPPORT_MAKE_TEST_THREAD_H

View file

@ -0,0 +1,452 @@
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef SUPPORT_TEST_MACROS_HPP
#define SUPPORT_TEST_MACROS_HPP
// Attempt to get STL specific macros like _LIBCPP_VERSION using the most
// minimal header possible. If we're testing libc++, we should use `<__config>`.
// If <__config> isn't available, fall back to <ciso646>.
#ifdef __has_include
# if __has_include("third_party/libcxx/__config")
# include "third_party/libcxx/__config"
# define TEST_IMP_INCLUDED_HEADER
# endif
#endif
#ifndef TEST_IMP_INCLUDED_HEADER
#include "third_party/libcxx/ciso646"
#endif
#define TEST_STRINGIZE_IMPL(...) #__VA_ARGS__
#define TEST_STRINGIZE(...) TEST_STRINGIZE_IMPL(__VA_ARGS__)
#define TEST_CONCAT1(X, Y) X##Y
#define TEST_CONCAT(X, Y) TEST_CONCAT1(X, Y)
#ifdef __has_feature
#define TEST_HAS_FEATURE(X) __has_feature(X)
#else
#define TEST_HAS_FEATURE(X) 0
#endif
#ifndef __has_include
#define __has_include(...) 0
#endif
#ifdef __has_extension
#define TEST_HAS_EXTENSION(X) __has_extension(X)
#else
#define TEST_HAS_EXTENSION(X) 0
#endif
#ifdef __has_warning
#define TEST_HAS_WARNING(X) __has_warning(X)
#else
#define TEST_HAS_WARNING(X) 0
#endif
#ifdef __has_builtin
#define TEST_HAS_BUILTIN(X) __has_builtin(X)
#else
#define TEST_HAS_BUILTIN(X) 0
#endif
#ifdef __is_identifier
// '__is_identifier' returns '0' if '__x' is a reserved identifier provided by
// the compiler and '1' otherwise.
#define TEST_HAS_BUILTIN_IDENTIFIER(X) !__is_identifier(X)
#else
#define TEST_HAS_BUILTIN_IDENTIFIER(X) 0
#endif
#if defined(__EDG__)
# define TEST_COMPILER_EDG
#elif defined(__clang__)
# define TEST_COMPILER_CLANG
# if defined(__apple_build_version__)
# define TEST_COMPILER_APPLE_CLANG
# endif
#elif defined(_MSC_VER)
# define TEST_COMPILER_MSVC
#elif defined(__GNUC__)
# define TEST_COMPILER_GCC
#endif
#if defined(__apple_build_version__)
// Given AppleClang XX.Y.Z, TEST_APPLE_CLANG_VER is XXYZ (e.g. AppleClang 14.0.3 => 1403)
#define TEST_APPLE_CLANG_VER (__apple_build_version__ / 10000)
#elif defined(__clang_major__)
#define TEST_CLANG_VER (__clang_major__ * 100) + __clang_minor__
#elif defined(__GNUC__)
// Given GCC XX.YY.ZZ, TEST_GCC_VER is XXYYZZ
#define TEST_GCC_VER ((__GNUC__ * 10000) + (__GNUC_MINOR__ * 100) + __GNUC_PATCHLEVEL__)
#endif
/* Make a nice name for the standard version */
#ifndef TEST_STD_VER
#if __cplusplus <= 199711L
# define TEST_STD_VER 3
#elif __cplusplus <= 201103L
# define TEST_STD_VER 11
#elif __cplusplus <= 201402L
# define TEST_STD_VER 14
#elif __cplusplus <= 201703L
# define TEST_STD_VER 17
#elif __cplusplus <= 202002L
# define TEST_STD_VER 20
#elif __cplusplus <= 202302L
# define TEST_STD_VER 23
#else
# define TEST_STD_VER 99 // greater than current standard
// This is deliberately different than _LIBCPP_STD_VER to discourage matching them up.
#endif
#endif
// Attempt to deduce the GLIBC version
#if (defined(__has_include) && __has_include(<features.h>)) || \
defined(__linux__)
#include <features.h>
#if defined(__GLIBC_PREREQ)
#define TEST_HAS_GLIBC
#define TEST_GLIBC_PREREQ(major, minor) __GLIBC_PREREQ(major, minor)
#endif
#endif
#if TEST_STD_VER >= 11
# define TEST_ALIGNOF(...) alignof(__VA_ARGS__)
# define TEST_ALIGNAS(...) alignas(__VA_ARGS__)
# define TEST_CONSTEXPR constexpr
# define TEST_NOEXCEPT noexcept
# define TEST_NOEXCEPT_FALSE noexcept(false)
# define TEST_NOEXCEPT_COND(...) noexcept(__VA_ARGS__)
#else
# if defined(TEST_COMPILER_CLANG)
# define TEST_ALIGNOF(...) _Alignof(__VA_ARGS__)
# else
# define TEST_ALIGNOF(...) __alignof(__VA_ARGS__)
# endif
# define TEST_ALIGNAS(...) __attribute__((__aligned__(__VA_ARGS__)))
# define TEST_CONSTEXPR
# define TEST_NOEXCEPT throw()
# define TEST_NOEXCEPT_FALSE
# define TEST_NOEXCEPT_COND(...)
#endif
#if TEST_STD_VER >= 11
# define TEST_THROW_SPEC(...)
#else
# define TEST_THROW_SPEC(...) throw(__VA_ARGS__)
#endif
#if defined(__cpp_lib_is_constant_evaluated) && __cpp_lib_is_constant_evaluated >= 201811L
# define TEST_IS_CONSTANT_EVALUATED std::is_constant_evaluated()
#elif TEST_HAS_BUILTIN(__builtin_is_constant_evaluated)
# define TEST_IS_CONSTANT_EVALUATED __builtin_is_constant_evaluated()
#else
# define TEST_IS_CONSTANT_EVALUATED false
#endif
#if TEST_STD_VER >= 14
# define TEST_CONSTEXPR_CXX14 constexpr
#else
# define TEST_CONSTEXPR_CXX14
#endif
#if TEST_STD_VER >= 17
# define TEST_CONSTEXPR_CXX17 constexpr
#else
# define TEST_CONSTEXPR_CXX17
#endif
#if TEST_STD_VER >= 20
# define TEST_CONSTEXPR_CXX20 constexpr
#else
# define TEST_CONSTEXPR_CXX20
#endif
#if TEST_STD_VER >= 23
# define TEST_CONSTEXPR_CXX23 constexpr
#else
# define TEST_CONSTEXPR_CXX23
#endif
#define TEST_ALIGNAS_TYPE(...) TEST_ALIGNAS(TEST_ALIGNOF(__VA_ARGS__))
#if !TEST_HAS_FEATURE(cxx_rtti) && !defined(__cpp_rtti) \
&& !defined(__GXX_RTTI)
#define TEST_HAS_NO_RTTI
#endif
#if !defined(TEST_HAS_NO_RTTI)
# define RTTI_ASSERT(X) assert(X)
#else
# define RTTI_ASSERT(X)
#endif
#if !TEST_HAS_FEATURE(cxx_exceptions) && !defined(__cpp_exceptions) \
&& !defined(__EXCEPTIONS)
#define TEST_HAS_NO_EXCEPTIONS
#endif
#if TEST_HAS_FEATURE(address_sanitizer) || TEST_HAS_FEATURE(hwaddress_sanitizer) || \
TEST_HAS_FEATURE(memory_sanitizer) || TEST_HAS_FEATURE(thread_sanitizer)
#define TEST_HAS_SANITIZERS
#define TEST_IS_EXECUTED_IN_A_SLOW_ENVIRONMENT
#endif
#if defined(_LIBCPP_NORETURN)
#define TEST_NORETURN _LIBCPP_NORETURN
#else
#define TEST_NORETURN [[noreturn]]
#endif
#if defined(_LIBCPP_HAS_NO_ALIGNED_ALLOCATION) || \
(!(TEST_STD_VER > 14 || \
(defined(__cpp_aligned_new) && __cpp_aligned_new >= 201606L)))
#define TEST_HAS_NO_ALIGNED_ALLOCATION
#endif
#if TEST_STD_VER > 17
#define TEST_CONSTINIT constinit
#elif defined(_LIBCPP_CONSTINIT)
#define TEST_CONSTINIT _LIBCPP_CONSTINIT
#else
#define TEST_CONSTINIT
#endif
#if TEST_STD_VER < 11
#define ASSERT_NOEXCEPT(...)
#define ASSERT_NOT_NOEXCEPT(...)
#else
#define ASSERT_NOEXCEPT(...) \
static_assert(noexcept(__VA_ARGS__), "Operation must be noexcept")
#define ASSERT_NOT_NOEXCEPT(...) \
static_assert(!noexcept(__VA_ARGS__), "Operation must NOT be noexcept")
#endif
/* Macros for testing libc++ specific behavior and extensions */
#if defined(_LIBCPP_VERSION)
#define LIBCPP_ASSERT(...) assert(__VA_ARGS__)
#define LIBCPP_STATIC_ASSERT(...) static_assert(__VA_ARGS__)
#define LIBCPP_ASSERT_NOEXCEPT(...) ASSERT_NOEXCEPT(__VA_ARGS__)
#define LIBCPP_ASSERT_NOT_NOEXCEPT(...) ASSERT_NOT_NOEXCEPT(__VA_ARGS__)
#define LIBCPP_ONLY(...) __VA_ARGS__
#else
#define LIBCPP_ASSERT(...) static_assert(true, "")
#define LIBCPP_STATIC_ASSERT(...) static_assert(true, "")
#define LIBCPP_ASSERT_NOEXCEPT(...) static_assert(true, "")
#define LIBCPP_ASSERT_NOT_NOEXCEPT(...) static_assert(true, "")
#define LIBCPP_ONLY(...) static_assert(true, "")
#endif
#if __has_cpp_attribute(nodiscard)
# define TEST_NODISCARD [[nodiscard]]
#else
# define TEST_NODISCARD
#endif
#define TEST_IGNORE_NODISCARD (void)
namespace test_macros_detail {
template <class T, class U>
struct is_same { enum { value = 0};} ;
template <class T>
struct is_same<T, T> { enum {value = 1}; };
} // namespace test_macros_detail
#define ASSERT_SAME_TYPE(...) \
static_assert((test_macros_detail::is_same<__VA_ARGS__>::value), \
"Types differ unexpectedly")
#ifndef TEST_HAS_NO_EXCEPTIONS
#define TEST_THROW(...) throw __VA_ARGS__
#else
#if defined(__GNUC__)
#define TEST_THROW(...) __builtin_abort()
#else
#include "libc/isystem/stdlib.h"
#define TEST_THROW(...) ::abort()
#endif
#endif
#if defined(__GNUC__) || defined(__clang__)
template <class Tp>
inline
void DoNotOptimize(Tp const& value) {
asm volatile("" : : "r,m"(value) : "memory");
}
template <class Tp>
inline void DoNotOptimize(Tp& value) {
#if defined(__clang__)
asm volatile("" : "+r,m"(value) : : "memory");
#else
asm volatile("" : "+m,r"(value) : : "memory");
#endif
}
#else
#include <intrin.h>
template <class Tp>
inline void DoNotOptimize(Tp const& value) {
const volatile void* volatile unused = __builtin_addressof(value);
static_cast<void>(unused);
_ReadWriteBarrier();
}
#endif
#if defined(__GNUC__)
#define TEST_ALWAYS_INLINE __attribute__((always_inline))
#define TEST_NOINLINE __attribute__((noinline))
#elif defined(_MSC_VER)
#define TEST_ALWAYS_INLINE __forceinline
#define TEST_NOINLINE __declspec(noinline)
#else
#define TEST_ALWAYS_INLINE
#define TEST_NOINLINE
#endif
#ifdef _WIN32
#define TEST_NOT_WIN32(...) ((void)0)
#else
#define TEST_NOT_WIN32(...) __VA_ARGS__
#endif
#if defined(TEST_WINDOWS_DLL) ||defined(__MVS__) || defined(_AIX)
// Macros for waiving cases when we can't count allocations done within
// the library implementation.
//
// On Windows, when libc++ is built as a DLL, references to operator new/delete
// within the DLL are bound at link time to the operator new/delete within
// the library; replacing them in the user executable doesn't override the
// calls within the library.
//
// The same goes on IBM zOS.
// The same goes on AIX.
#define ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(...) ((void)(__VA_ARGS__))
#define TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS 0
#else
#define ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(...) assert(__VA_ARGS__)
#define TEST_SUPPORTS_LIBRARY_INTERNAL_ALLOCATIONS 1
#endif
#if (defined(TEST_WINDOWS_DLL) && !defined(_MSC_VER)) || \
defined(__MVS__)
// Normally, a replaced e.g. 'operator new' ends up used if the user code
// does a call to e.g. 'operator new[]'; it's enough to replace the base
// versions and have it override all of them.
//
// When the fallback operators are located within the libc++ library and we
// can't override the calls within it (see above), this fallback mechanism
// doesn't work either.
//
// On Windows, when using the MSVC vcruntime, the operator new/delete fallbacks
// are linked separately from the libc++ library, linked statically into
// the end user executable, and these fallbacks work even in DLL configurations.
// In MinGW configurations when built as a DLL, and on zOS, these fallbacks
// don't work though.
#define ASSERT_WITH_OPERATOR_NEW_FALLBACKS(...) ((void)(__VA_ARGS__))
#else
#define ASSERT_WITH_OPERATOR_NEW_FALLBACKS(...) assert(__VA_ARGS__)
#endif
#ifdef _WIN32
#define TEST_WIN_NO_FILESYSTEM_PERMS_NONE
#endif
// Support for carving out parts of the test suite, like removing wide characters, etc.
#if defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
# define TEST_HAS_NO_WIDE_CHARACTERS
#endif
#if defined(_LIBCPP_HAS_NO_UNICODE)
# define TEST_HAS_NO_UNICODE
#elif defined(_MSVC_EXECUTION_CHARACTER_SET) && _MSVC_EXECUTION_CHARACTER_SET != 65001
# define TEST_HAS_NO_UNICODE
#endif
#if defined(_LIBCPP_HAS_NO_INT128) || defined(_MSVC_STL_VERSION)
# define TEST_HAS_NO_INT128
#endif
#if defined(_LIBCPP_HAS_NO_LOCALIZATION)
# define TEST_HAS_NO_LOCALIZATION
#endif
#if TEST_STD_VER <= 17 || !defined(__cpp_char8_t)
# define TEST_HAS_NO_CHAR8_T
#endif
#if defined(_LIBCPP_HAS_NO_THREADS)
# define TEST_HAS_NO_THREADS
#endif
#if defined(_LIBCPP_HAS_NO_FILESYSTEM)
# define TEST_HAS_NO_FILESYSTEM
#endif
#if defined(_LIBCPP_HAS_NO_FGETPOS_FSETPOS)
# define TEST_HAS_NO_FGETPOS_FSETPOS
#endif
#if defined(_LIBCPP_HAS_NO_C8RTOMB_MBRTOC8)
# define TEST_HAS_NO_C8RTOMB_MBRTOC8
#endif
#if defined(_LIBCPP_HAS_NO_RANDOM_DEVICE)
# define TEST_HAS_NO_RANDOM_DEVICE
#endif
#if defined(TEST_COMPILER_CLANG)
# define TEST_DIAGNOSTIC_PUSH _Pragma("clang diagnostic push")
# define TEST_DIAGNOSTIC_POP _Pragma("clang diagnostic pop")
# define TEST_CLANG_DIAGNOSTIC_IGNORED(str) _Pragma(TEST_STRINGIZE(clang diagnostic ignored str))
# define TEST_GCC_DIAGNOSTIC_IGNORED(str)
# define TEST_MSVC_DIAGNOSTIC_IGNORED(num)
#elif defined(TEST_COMPILER_GCC)
# define TEST_DIAGNOSTIC_PUSH _Pragma("GCC diagnostic push")
# define TEST_DIAGNOSTIC_POP _Pragma("GCC diagnostic pop")
# define TEST_CLANG_DIAGNOSTIC_IGNORED(str)
# define TEST_GCC_DIAGNOSTIC_IGNORED(str) _Pragma(TEST_STRINGIZE(GCC diagnostic ignored str))
# define TEST_MSVC_DIAGNOSTIC_IGNORED(num)
#elif defined(TEST_COMPILER_MSVC)
# define TEST_DIAGNOSTIC_PUSH _Pragma("warning(push)")
# define TEST_DIAGNOSTIC_POP _Pragma("warning(pop)")
# define TEST_CLANG_DIAGNOSTIC_IGNORED(str)
# define TEST_GCC_DIAGNOSTIC_IGNORED(str)
# define TEST_MSVC_DIAGNOSTIC_IGNORED(num) _Pragma(TEST_STRINGIZE(warning(disable: num)))
#else
# define TEST_DIAGNOSTIC_PUSH
# define TEST_DIAGNOSTIC_POP
# define TEST_CLANG_DIAGNOSTIC_IGNORED(str)
# define TEST_GCC_DIAGNOSTIC_IGNORED(str)
# define TEST_MSVC_DIAGNOSTIC_IGNORED(num)
#endif
#if __has_cpp_attribute(msvc::no_unique_address)
#define TEST_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
#elif __has_cpp_attribute(no_unique_address)
#define TEST_NO_UNIQUE_ADDRESS [[no_unique_address]]
#else
#define TEST_NO_UNIQUE_ADDRESS
#endif
#ifdef _LIBCPP_SHORT_WCHAR
# define TEST_SHORT_WCHAR
#endif
// This is a temporary workaround for user-defined `operator new` definitions
// not being picked up on Apple platforms in some circumstances. This is under
// investigation and should be short-lived.
#ifdef __APPLE__
# define TEST_WORKAROUND_BUG_109234844_WEAK __attribute__((weak))
#else
# define TEST_WORKAROUND_BUG_109234844_WEAK /* nothing */
#endif
#endif // SUPPORT_TEST_MACROS_HPP

179
third_party/libcxxabi/test/BUILD.mk vendored Normal file
View file

@ -0,0 +1,179 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
ifeq ($(MODE), )
PKGS += THIRD_PARTY_LIBCXXABI_TEST
THIRD_PARTY_LIBCXXABI_TEST_A = o/$(MODE)/third_party/libcxxabi/test/test.a
THIRD_PARTY_LIBCXXABI_TEST_HDRS = \
third_party/libcxxabi/libcxx/test/support/make_test_thread.hh \
third_party/libcxxabi/libcxx/test/support/test_macros.hh \
third_party/libcxxabi/test/support/timer.hh
THIRD_PARTY_LIBCXXABI_TEST_SRCS = \
third_party/libcxxabi/test/catch_array_02.pass.cc \
third_party/libcxxabi/test/catch_class_01.pass.cc \
third_party/libcxxabi/test/catch_class_02.pass.cc \
third_party/libcxxabi/test/catch_class_03.pass.cc \
third_party/libcxxabi/test/catch_class_04.pass.cc \
third_party/libcxxabi/test/catch_const_pointer_nullptr.pass.cc \
third_party/libcxxabi/test/catch_function_02.pass.cc \
third_party/libcxxabi/test/catch_function_03.pass.cc \
third_party/libcxxabi/test/catch_in_noexcept.pass.cc \
third_party/libcxxabi/test/catch_member_data_pointer_01.pass.cc \
third_party/libcxxabi/test/catch_member_pointer_nullptr.pass.cc \
third_party/libcxxabi/test/catch_pointer_nullptr.pass.cc \
third_party/libcxxabi/test/catch_pointer_reference.pass.cc \
third_party/libcxxabi/test/catch_ptr.pass.cc \
third_party/libcxxabi/test/catch_ptr_02.pass.cc \
third_party/libcxxabi/test/catch_reference_nullptr.pass.cc \
third_party/libcxxabi/test/cxa_bad_cast.pass.cc \
third_party/libcxxabi/test/cxa_bad_typeid.pass.cc \
third_party/libcxxabi/test/cxa_thread_atexit_test.pass.cc \
third_party/libcxxabi/test/cxa_vec_new_overflow_PR41395.pass.cc \
third_party/libcxxabi/test/dynamic_cast.pass.cc \
third_party/libcxxabi/test/dynamic_cast3.pass.cc \
third_party/libcxxabi/test/dynamic_cast5.pass.cc \
third_party/libcxxabi/test/dynamic_cast14.pass.cc \
third_party/libcxxabi/test/dynamic_cast_stress.pass.cc \
third_party/libcxxabi/test/exception_object_alignment.pass.cc \
third_party/libcxxabi/test/exception_object_alignment.2.pass.cc \
third_party/libcxxabi/test/guard_test_basic.pass.cc \
third_party/libcxxabi/test/guard_threaded_test.pass.cc \
third_party/libcxxabi/test/incomplete_type.sh.cc \
third_party/libcxxabi/test/inherited_exception.pass.cc \
third_party/libcxxabi/test/test_aux_runtime.pass.cc \
third_party/libcxxabi/test/test_aux_runtime_op_array_new.pass.cc\
third_party/libcxxabi/test/test_demangle.pass.cc \
third_party/libcxxabi/test/test_exception_address_alignment.pass.cc \
third_party/libcxxabi/test/test_exception_storage.pass.cc \
third_party/libcxxabi/test/test_fallback_malloc.pass.cc \
third_party/libcxxabi/test/test_guard.pass.cc \
third_party/libcxxabi/test/test_vector1.pass.cc \
third_party/libcxxabi/test/test_vector2.pass.cc \
third_party/libcxxabi/test/test_vector3.pass.cc \
third_party/libcxxabi/test/uncaught_exception.pass.cc \
third_party/libcxxabi/test/uncaught_exceptions.pass.cc \
third_party/libcxxabi/test/unittest_demangle.pass.cc \
third_party/libcxxabi/test/unwind_01.pass.cc \
third_party/libcxxabi/test/unwind_02.pass.cc \
third_party/libcxxabi/test/unwind_03.pass.cc \
third_party/libcxxabi/test/unwind_04.pass.cc \
third_party/libcxxabi/test/unwind_05.pass.cc \
third_party/libcxxabi/test/unwind_06.pass.cc
# TODO: Add this test when #1073 is fixed
THIRD_PARTY_LIBCXXABI_TEST_SRCS_FAILING_COSMO = \
third_party/libcxxabi/test/thread_local_destruction_order.pass.cc
THIRD_PARTY_LIBCXXABI_TEST_SRCS_FAILING_GCC = \
third_party/libcxxabi/test/catch_array_01.pass.cc \
third_party/libcxxabi/test/catch_function_01.pass.cc \
third_party/libcxxabi/test/catch_member_function_pointer_01.pass.cc \
third_party/libcxxabi/test/catch_member_function_pointer_02.pass.cc
# Works if run, but fails to compile on GitHub Actions with an OOM
THIRD_PARTYLIBCXXABI_TEST_SRCS_COMPILE_OOM = \
third_party/libcxxabi/test/catch_multi_level_pointer.pass.cc
THIRD_PARTY_LIBCXXABI_TEST_COMS = \
$(THIRD_PARTY_LIBCXXABI_TEST_SRCS:%.cc=o/$(MODE)/%.com)
THIRD_PARTY_LIBCXXABI_TEST_TESTS = \
$(THIRD_PARTY_LIBCXXABI_TEST_COMS:%=%.ok)
THIRD_PARTY_LIBCXXABI_TEST_OBJS = \
$(THIRD_PARTY_LIBCXXABI_TEST_SRCS:%.cc=o/$(MODE)/%.o) \
o/$(MODE)/third_party/libcxxabi/test/incomplete_type.sh.one.o \
o/$(MODE)/third_party/libcxxabi/test/incomplete_type.sh.two.o
THIRD_PARTY_LIBCXXABI_TEST_OBJS_WNO_EXCEPTIONS = \
o/$(MODE)/third_party/libcxxabi/test/catch_class_03.pass.o \
o/$(MODE)/third_party/libcxxabi/test/catch_class_04.pass.o \
o/$(MODE)/third_party/libcxxabi/test/catch_ptr.pass.o \
o/$(MODE)/third_party/libcxxabi/test/catch_ptr_02.pass.o \
o/$(MODE)/third_party/libcxxabi/test/inherited_exception.pass.o
THIRD_PARTY_LIBCXXABI_TEST_OBJS_CPP14 = \
o/$(MODE)/third_party/libcxxabi/test/unwind_02.pass.o \
o/$(MODE)/third_party/libcxxabi/test/unwind_03.pass.o \
o/$(MODE)/third_party/libcxxabi/test/unwind_04.pass.o \
o/$(MODE)/third_party/libcxxabi/test/unwind_05.pass.o
THIRD_PARTY_LIBCXXABI_TEST_BINS = \
$(THIRD_PARTY_LIBCXXABI_TEST_COMS) \
$(THIRD_PARTY_LIBCXXABI_TEST_COMS:%=%.dbg)
THIRD_PARTY_LIBCXXABI_TEST_CHECKS = \
$(THIRD_PARTY_LIBCXXABI_TEST_COMS:%=%.runs) \
$(THIRD_PARTY_LIBCXXABI_TEST_HDRS:%=o/$(MODE)/%.ok)
THIRD_PARTY_LIBCXXABI_TEST_DIRECTDEPS = \
LIBC_NEXGEN32E \
THIRD_PARTY_LIBCXX \
THIRD_PARTY_LIBCXXABI
THIRD_PARTY_LIBCXXABI_TEST_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_LIBCXXABI_TEST_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_LIBCXXABI_TEST_A): \
$(THIRD_PARTY_LIBCXXABI_TEST_A).pkg
$(THIRD_PARTY_LIBCXXABI_TEST_A).pkg: \
$(foreach x,$(THIRD_PARTY_LIBCXXABI_TEST_DIRECTDEPS),$($(x)_A).pkg)
o/$(MODE)/third_party/libcxxabi/test/%.com.dbg: \
$(THIRD_PARTY_LIBCXXABI_TEST_DEPS) \
$(THIRD_PARTY_LIBCXXABI_TEST_A) \
o/$(MODE)/third_party/libcxxabi/test/%.o \
$(THIRD_PARTY_LIBCXXABI_TEST_A).pkg \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
# TODO: Remove constinit hacks when we have C++20
$(THIRD_PARTY_LIBCXXABI_TEST_OBJS): private \
CXXFLAGS += \
-fexceptions \
-frtti \
-D_LIBCXXABI_BUILDING_LIBRARY \
-D_LIBCPP_BUILDING_LIBRARY \
-D_LIBCPP_CONSTINIT=__constinit
$(THIRD_PARTY_LIBCXXABI_TEST_OBJS_WNO_EXCEPTIONS): private \
CXXFLAGS += \
-Wno-exceptions
$(THIRD_PARTY_LIBCXXABI_TEST_OBJS_CPP14): private \
CXXFLAGS += \
-std=gnu++14
o/$(MODE)/third_party/libcxxabi/test/guard_test_basic.pass.o: private \
CXXFLAGS += \
-Wno-invalid-memory-model
o/$(MODE)/third_party/libcxxabi/test/incomplete_type.sh.one.o: private \
CXXFLAGS += \
-Wno-unreachable-code
o/$(MODE)/third_party/libcxxabi/test/incomplete_type.sh.two.o: private \
CXXFLAGS += \
-Wno-unreachable-code \
-DTU_ONE
o/$(MODE)/third_party/libcxxabi/test/incomplete_type.sh.com.dbg: \
$(THIRD_PARTY_LIBCXXABI_TEST_DEPS) \
$(THIRD_PARTY_LIBCXXABI_TEST_A) \
o/$(MODE)/third_party/libcxxabi/test/incomplete_type.sh.one.o \
o/$(MODE)/third_party/libcxxabi/test/incomplete_type.sh.two.o \
$(THIRD_PARTY_LIBCXXABI_TEST_A).pkg \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
endif
.PHONY: o/$(MODE)/third_party/libcxxabi/test
o/$(MODE)/third_party/libcxxabi/test: \
$(THIRD_PARTY_LIBCXXABI_TEST_BINS) \
$(THIRD_PARTY_LIBCXXABI_TEST_CHECKS)

View file

@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Can you have a catch clause of array type that catches anything?
// GCC incorrectly allows array types to be caught by reference.
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69372
// XFAIL: gcc
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/cassert"
int main(int, char**)
{
typedef char Array[4];
Array a = {'H', 'i', '!', 0};
try
{
throw a; // converts to char*
assert(false);
}
catch (Array& b) // can't catch char*
{
assert(false);
}
catch (...)
{
}
return 0;
}

View file

@ -0,0 +1,32 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Can you have a catch clause of array type that catches anything?
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/cassert"
int main(int, char**)
{
typedef char Array[4];
Array a = {'H', 'i', '!', 0};
try
{
throw a; // converts to char*
assert(false);
}
catch (Array b) // equivalent to char*
{
}
catch (...)
{
assert(false);
}
return 0;
}

View file

@ -0,0 +1,61 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
#include <exception>
#include <stdlib.h>
#include <assert.h>
struct A
{
static int count;
int id_;
explicit A(int id) : id_(id) {count++;}
A(const A& a) : id_(a.id_) {count++;}
~A() {count--;}
};
int A::count = 0;
void f1()
{
throw A(3);
}
void f2()
{
try
{
assert(A::count == 0);
f1();
}
catch (A a)
{
assert(A::count != 0);
assert(a.id_ == 3);
throw;
}
}
int main(int, char**)
{
try
{
f2();
assert(false);
}
catch (const A& a)
{
assert(A::count != 0);
assert(a.id_ == 3);
}
assert(A::count == 0);
return 0;
}

View file

@ -0,0 +1,86 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/exception"
#include "libc/isystem/stdlib.h"
#include "libc/isystem/assert.h"
struct B
{
static int count;
int id_;
explicit B(int id) : id_(id) {count++;}
B(const B& a) : id_(a.id_) {count++;}
~B() {count--;}
};
int B::count = 0;
struct A
: B
{
static int count;
int id_;
explicit A(int id) : B(id-1), id_(id) {count++;}
A(const A& a) : B(a.id_-1), id_(a.id_) {count++;}
~A() {count--;}
};
int A::count = 0;
void f1()
{
assert(A::count == 0);
assert(B::count == 0);
A a(3);
assert(A::count == 1);
assert(B::count == 1);
throw a;
assert(false);
}
void f2()
{
try
{
assert(A::count == 0);
f1();
assert(false);
}
catch (A a)
{
assert(A::count != 0);
assert(B::count != 0);
assert(a.id_ == 3);
throw;
}
catch (B b)
{
assert(false);
}
}
int main(int, char**)
{
try
{
f2();
assert(false);
}
catch (const B& b)
{
assert(B::count != 0);
assert(b.id_ == 2);
}
assert(A::count == 0);
assert(B::count == 0);
return 0;
}

View file

@ -0,0 +1,198 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/*
This test checks that adjustedPtr is correct as there exist offsets in this
object for the various subobjects, all of which have a unique id_ to
check against.
*/
// UNSUPPORTED: no-exceptions
// Compilers emit warnings about exceptions of type 'Child' being caught by
// an earlier handler of type 'Base'. Congrats, you've just diagnosed the
// behavior under test.
// ADDITIONAL_COMPILE_FLAGS: -Wno-exceptions
#include "third_party/libcxx/exception"
#include "libc/isystem/stdlib.h"
#include "libc/isystem/assert.h"
struct B
{
static int count;
int id_;
explicit B(int id) : id_(id) {count++;}
B(const B& a) : id_(a.id_) {count++;}
~B() {count--;}
};
int B::count = 0;
struct C1
: B
{
static int count;
int id_;
explicit C1(int id) : B(id-2), id_(id) {count++;}
C1(const C1& a) : B(a.id_-2), id_(a.id_) {count++;}
~C1() {count--;}
};
int C1::count = 0;
struct C2
: B
{
static int count;
int id_;
explicit C2(int id) : B(id-2), id_(id) {count++;}
C2(const C2& a) : B(a.id_-2), id_(a.id_) {count++;}
~C2() {count--;}
};
int C2::count = 0;
struct A
: C1, C2
{
static int count;
int id_;
explicit A(int id) : C1(id-1), C2(id-2), id_(id) {count++;}
A(const A& a) : C1(a.id_-1), C2(a.id_-2), id_(a.id_) {count++;}
~A() {count--;}
};
int A::count = 0;
void f1()
{
assert(A::count == 0);
assert(C1::count == 0);
assert(C2::count == 0);
assert(B::count == 0);
A a(5);
assert(A::count == 1);
assert(C1::count == 1);
assert(C2::count == 1);
assert(B::count == 2);
assert(a.id_ == 5);
assert(static_cast<C1&>(a).id_ == 4);
assert(static_cast<C2&>(a).id_ == 3);
assert(static_cast<B&>(static_cast<C1&>(a)).id_ == 2);
assert(static_cast<B&>(static_cast<C2&>(a)).id_ == 1);
throw a;
assert(false);
}
void f2()
{
try
{
assert(A::count == 0);
assert(C1::count == 0);
assert(C2::count == 0);
assert(B::count == 0);
f1();
assert(false);
}
catch (const A& a) // can catch A
{
assert(a.id_ == 5);
assert(static_cast<const C1&>(a).id_ == 4);
assert(static_cast<const C2&>(a).id_ == 3);
assert(static_cast<const B&>(static_cast<const C1&>(a)).id_ == 2);
assert(static_cast<const B&>(static_cast<const C2&>(a)).id_ == 1);
throw;
}
catch (const C1&)
{
assert(false);
}
catch (const C2&)
{
assert(false);
}
catch (const B&)
{
assert(false);
}
}
void f3()
{
try
{
assert(A::count == 0);
assert(C1::count == 0);
assert(C2::count == 0);
assert(B::count == 0);
f2();
assert(false);
}
catch (const B& a) // can not catch B (ambiguous base)
{
assert(false);
}
catch (const C1& c1) // can catch C1
{
assert(c1.id_ == 4);
assert(static_cast<const B&>(c1).id_ == 2);
throw;
}
catch (const C2&)
{
assert(false);
}
}
void f4()
{
try
{
assert(A::count == 0);
assert(C1::count == 0);
assert(C2::count == 0);
assert(B::count == 0);
f3();
assert(false);
}
catch (const B& a) // can not catch B (ambiguous base)
{
assert(false);
}
catch (const C2& c2) // can catch C2
{
assert(c2.id_ == 3);
assert(static_cast<const B&>(c2).id_ == 1);
throw;
}
catch (const C1&)
{
assert(false);
}
}
int main(int, char**)
{
try
{
f4();
assert(false);
}
catch (...)
{
}
assert(A::count == 0);
assert(C1::count == 0);
assert(C2::count == 0);
assert(B::count == 0);
return 0;
}

View file

@ -0,0 +1,221 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/*
This test checks that adjustedPtr is correct as there exist offsets in this
object for the various subobjects, all of which have a unique id_ to
check against. It also checks that virtual bases work properly
*/
// UNSUPPORTED: no-exceptions
// Compilers emit warnings about exceptions of type 'Child' being caught by
// an earlier handler of type 'Base'. Congrats, you've just diagnosed the
// behavior under test.
// ADDITIONAL_COMPILE_FLAGS: -Wno-exceptions
#include "third_party/libcxx/exception"
#include "libc/isystem/stdlib.h"
#include "libc/isystem/assert.h"
struct B
{
static int count;
int id_;
explicit B(int id) : id_(id) {count++;}
B(const B& a) : id_(a.id_) {count++;}
~B() {count--;}
};
int B::count = 0;
struct C1
: virtual B
{
static int count;
int id_;
explicit C1(int id) : B(id-2), id_(id) {count++;}
C1(const C1& a) : B(a.id_-2), id_(a.id_) {count++;}
~C1() {count--;}
};
int C1::count = 0;
struct C2
: virtual private B
{
static int count;
int id_;
explicit C2(int id) : B(id-2), id_(id) {count++;}
C2(const C2& a) : B(a.id_-2), id_(a.id_) {count++;}
~C2() {count--;}
};
int C2::count = 0;
struct A
: C1, C2
{
static int count;
int id_;
explicit A(int id) : B(id+3), C1(id-1), C2(id-2), id_(id) {count++;}
A(const A& a) : B(a.id_+3), C1(a.id_-1), C2(a.id_-2), id_(a.id_) {count++;}
~A() {count--;}
};
int A::count = 0;
void f1()
{
assert(A::count == 0);
assert(C1::count == 0);
assert(C2::count == 0);
assert(B::count == 0);
A a(5);
assert(A::count == 1);
assert(C1::count == 1);
assert(C2::count == 1);
assert(B::count == 1);
assert(a.id_ == 5);
assert(static_cast<C1&>(a).id_ == 4);
assert(static_cast<C2&>(a).id_ == 3);
assert(static_cast<B&>(a).id_ == 8);
throw a;
assert(false);
}
void f2()
{
try
{
assert(A::count == 0);
assert(C1::count == 0);
assert(C2::count == 0);
assert(B::count == 0);
f1();
assert(false);
}
catch (const A& a) // can catch A
{
assert(a.id_ == 5);
assert(static_cast<const C1&>(a).id_ == 4);
assert(static_cast<const C2&>(a).id_ == 3);
assert(static_cast<const B&>(a).id_ == 8);
throw;
}
catch (const C1&)
{
assert(false);
}
catch (const C2&)
{
assert(false);
}
catch (const B&)
{
assert(false);
}
}
void f3()
{
try
{
assert(A::count == 0);
assert(C1::count == 0);
assert(C2::count == 0);
assert(B::count == 0);
f2();
assert(false);
}
catch (const B& a) // can catch B
{
assert(static_cast<const B&>(a).id_ == 8);
throw;
}
catch (const C1& c1)
{
assert(false);
}
catch (const C2&)
{
assert(false);
}
}
void f4()
{
try
{
assert(A::count == 0);
assert(C1::count == 0);
assert(C2::count == 0);
assert(B::count == 0);
f3();
assert(false);
}
catch (const C2& c2) // can catch C2
{
assert(c2.id_ == 3);
throw;
}
catch (const B& a) // can not catch B (ambiguous base)
{
assert(false);
}
catch (const C1&)
{
assert(false);
}
}
void f5()
{
try
{
assert(A::count == 0);
assert(C1::count == 0);
assert(C2::count == 0);
assert(B::count == 0);
f4();
assert(false);
}
catch (const C1& c1) // can catch C1
{
assert(c1.id_ == 4);
assert(static_cast<const B&>(c1).id_ == 8);
throw;
}
catch (const B& a)
{
assert(false);
}
catch (const C2&)
{
assert(false);
}
}
int main(int, char**)
{
try
{
f5();
assert(false);
}
catch (...)
{
}
assert(A::count == 0);
assert(C1::count == 0);
assert(C2::count == 0);
assert(B::count == 0);
return 0;
}

View file

@ -0,0 +1,148 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/cassert"
// Clang emits warnings about exceptions of type 'Child' being caught by
// an earlier handler of type 'Base'. Congrats clang, you've just
// diagnosed the behavior under test.
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wexceptions"
#endif
#if __has_feature(cxx_nullptr)
struct A {};
void test1()
{
try
{
throw nullptr;
assert(false);
}
catch (A* p)
{
assert(!p);
}
catch (const A*)
{
assert(false);
}
}
void test2()
{
try
{
throw nullptr;
assert(false);
}
catch (const A* p)
{
assert(!p);
}
catch (A*)
{
assert(false);
}
}
void test3()
{
try
{
throw nullptr;
assert(false);
}
catch (const A* const p)
{
assert(!p);
}
catch (A*)
{
assert(false);
}
}
void test4()
{
try
{
throw nullptr;
assert(false);
}
catch (A* p)
{
assert(!p);
}
catch (const A* const)
{
assert(false);
}
}
void test5()
{
try
{
throw nullptr;
assert(false);
}
catch (A const* p)
{
assert(!p);
}
catch (A*)
{
assert(false);
}
}
void test6()
{
try
{
throw nullptr;
assert(false);
}
catch (A* p)
{
assert(!p);
}
catch (A const*)
{
assert(false);
}
}
#else
void test1() {}
void test2() {}
void test3() {}
void test4() {}
void test5() {}
void test6() {}
#endif
int main(int, char**) {
test1();
test2();
test3();
test4();
test5();
test6();
return 0;
}

View file

@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Can you have a catch clause of array type that catches anything?
// GCC incorrectly allows function pointer to be caught by reference.
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69372
// XFAIL: gcc
// UNSUPPORTED: no-exceptions
// 65ace9daa360 made it in the dylib in macOS 10.11
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10}}
#include "third_party/libcxx/cassert"
template <class Tp>
bool can_convert(Tp) { return true; }
template <class>
bool can_convert(...) { return false; }
void f() {}
int main(int, char**)
{
typedef void Function();
assert(!can_convert<Function&>(&f));
assert(!can_convert<void*>(&f));
try
{
throw f; // converts to void (*)()
assert(false);
}
catch (Function& b) // can't catch void (*)()
{
assert(false);
}
catch (void*) // can't catch as void*
{
assert(false);
}
catch(Function*)
{
}
catch (...)
{
assert(false);
}
return 0;
}

View file

@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Can you have a catch clause of array type that catches anything?
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/cassert"
void f() {}
int main(int, char**)
{
typedef void Function();
try
{
throw f; // converts to void (*)()
assert(false);
}
catch (Function b) // equivalent to void (*)()
{
}
catch (...)
{
assert(false);
}
return 0;
}

View file

@ -0,0 +1,69 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Can a noexcept function pointer be caught by a non-noexcept catch clause?
// UNSUPPORTED: c++03, c++11, c++14
// UNSUPPORTED: no-exceptions
// Support for catching a function pointer including noexcept was shipped in macOS 10.13
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11|12}}
#include "third_party/libcxx/cassert"
template<bool Noexcept> void f() noexcept(Noexcept) {}
template<bool Noexcept> using FnType = void() noexcept(Noexcept);
template<bool ThrowNoexcept, bool CatchNoexcept>
void check()
{
try
{
auto *p = f<ThrowNoexcept>;
throw p;
assert(false);
}
catch (FnType<CatchNoexcept> *p)
{
assert(ThrowNoexcept || !CatchNoexcept);
assert(p == &f<ThrowNoexcept>);
}
catch (...)
{
assert(!ThrowNoexcept && CatchNoexcept);
}
}
void check_deep() {
auto *p = f<true>;
try
{
throw &p;
}
catch (FnType<false> **q)
{
assert(false);
}
catch (FnType<true> **q)
{
}
catch (...)
{
assert(false);
}
}
int main(int, char**)
{
check<false, false>();
check<false, true>();
check<true, false>();
check<true, true>();
check_deep();
return 0;
}

View file

@ -0,0 +1,38 @@
//===---------------------- catch_in_noexcept.cpp--------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/exception"
#include "libc/isystem/stdlib.h"
#include "libc/isystem/assert.h"
struct A {};
// Despite being marked as noexcept, this function must have an EHT entry that
// is not 'cantunwind', so that the unwinder can correctly deal with the throw.
void f1() noexcept
{
try {
A a;
throw a;
assert(false);
} catch (...) {
assert(true);
return;
}
assert(false);
}
int main(int, char**)
{
f1();
return 0;
}

View file

@ -0,0 +1,179 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// 1b00fc5d8133 made it in the dylib in macOS 10.11
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10}}
#include "third_party/libcxx/cassert"
struct A
{
A() : i(0), j(0) {} // explicitly initialize 'i' to prevent warnings
const int i;
int j;
};
typedef const int A::*md1;
typedef int A::*md2;
struct B : public A
{
B() : k(0), l(0) {} // explicitly initialize 'k' to prevent warnings.
const int k;
int l;
};
typedef const int B::*der1;
typedef int B::*der2;
void test1()
{
try
{
throw &A::i;
assert(false);
}
catch (md2)
{
assert(false);
}
catch (md1)
{
}
}
// Check that cv qualified conversions are allowed.
void test2()
{
try
{
throw &A::j;
}
catch (md2)
{
}
catch (...)
{
assert(false);
}
try
{
throw &A::j;
assert(false);
}
catch (md1)
{
}
catch (...)
{
assert(false);
}
}
// Check that Base -> Derived conversions are NOT allowed.
void test3()
{
try
{
throw &A::i;
assert(false);
}
catch (md2)
{
assert(false);
}
catch (der2)
{
assert(false);
}
catch (der1)
{
assert(false);
}
catch (md1)
{
}
}
// Check that Base -> Derived conversions NOT are allowed with different cv
// qualifiers.
void test4()
{
try
{
throw &A::j;
assert(false);
}
catch (der2)
{
assert(false);
}
catch (der1)
{
assert(false);
}
catch (md2)
{
}
catch (...)
{
assert(false);
}
}
// Check that no Derived -> Base conversions are allowed.
void test5()
{
try
{
throw &B::k;
assert(false);
}
catch (md1)
{
assert(false);
}
catch (md2)
{
assert(false);
}
catch (der1)
{
}
try
{
throw &B::l;
assert(false);
}
catch (md1)
{
assert(false);
}
catch (md2)
{
assert(false);
}
catch (der2)
{
}
}
int main(int, char**)
{
test1();
test2();
test3();
test4();
test5();
return 0;
}

View file

@ -0,0 +1,172 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// GCC incorrectly allows PMF type "void (T::*)()" to be caught as "void (T::*)() const"
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69375
// XFAIL: gcc
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/cassert"
struct A
{
void foo() {}
void bar() const {}
};
typedef void (A::*mf1)();
typedef void (A::*mf2)() const;
struct B : public A
{
};
typedef void (B::*dmf1)();
typedef void (B::*dmf2)() const;
template <class Tp>
bool can_convert(Tp) { return true; }
template <class>
bool can_convert(...) { return false; }
void test1()
{
try
{
throw &A::foo;
assert(false);
}
catch (mf2)
{
assert(false);
}
catch (mf1)
{
}
}
void test2()
{
try
{
throw &A::bar;
assert(false);
}
catch (mf1)
{
assert(false);
}
catch (mf2)
{
}
}
void test_derived()
{
try
{
throw (mf1)0;
assert(false);
}
catch (dmf2)
{
assert(false);
}
catch (dmf1)
{
assert(false);
}
catch (mf1)
{
}
try
{
throw (mf2)0;
assert(false);
}
catch (dmf1)
{
assert(false);
}
catch (dmf2)
{
assert(false);
}
catch (mf2)
{
}
assert(!can_convert<mf1>((dmf1)0));
assert(!can_convert<mf2>((dmf1)0));
try
{
throw (dmf1)0;
assert(false);
}
catch (mf2)
{
assert(false);
}
catch (mf1)
{
assert(false);
}
catch (...)
{
}
assert(!can_convert<mf1>((dmf2)0));
assert(!can_convert<mf2>((dmf2)0));
try
{
throw (dmf2)0;
assert(false);
}
catch (mf2)
{
assert(false);
}
catch (mf1)
{
assert(false);
}
catch (...)
{
}
}
void test_void()
{
assert(!can_convert<void*>(&A::foo));
try
{
throw &A::foo;
assert(false);
}
catch (void*)
{
assert(false);
}
catch(...)
{
}
}
int main(int, char**)
{
test1();
test2();
test_derived();
test_void();
return 0;
}

View file

@ -0,0 +1,75 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Can a noexcept member function pointer be caught by a non-noexcept catch clause?
// UNSUPPORTED: c++03, c++11, c++14
// UNSUPPORTED: no-exceptions
// Support for catching a function pointer including noexcept was shipped in macOS 10.13
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11|12}}
// GCC supports noexcept function types but this test still fails.
// This is likely a bug in their implementation. Investigation needed.
// XFAIL: gcc-11, gcc-12, gcc-13
#include "third_party/libcxx/cassert"
struct X {
template<bool Noexcept> void f() noexcept(Noexcept) {}
};
template<bool Noexcept> using FnType = void (X::*)() noexcept(Noexcept);
template<bool ThrowNoexcept, bool CatchNoexcept>
void check()
{
try
{
auto p = &X::f<ThrowNoexcept>;
throw p;
assert(false);
}
catch (FnType<CatchNoexcept> p)
{
assert(ThrowNoexcept || !CatchNoexcept);
assert(p == &X::f<ThrowNoexcept>);
}
catch (...)
{
assert(!ThrowNoexcept && CatchNoexcept);
}
}
void check_deep() {
FnType<true> p = &X::f<true>;
try
{
throw &p;
}
catch (FnType<false> *q)
{
assert(false);
}
catch (FnType<true> *q)
{
}
catch (...)
{
assert(false);
}
}
int main(int, char**)
{
check<false, false>();
check<false, true>();
check<true, false>();
check<true, true>();
check_deep();
return 0;
}

View file

@ -0,0 +1,80 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Catching an exception thrown as nullptr was not properly handled before
// 2f984cab4fa7, which landed in macOS 10.13
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11|12}}
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/cassert"
#if __has_feature(cxx_nullptr)
struct A
{
const int i;
int j;
};
typedef const int A::*md1;
typedef int A::*md2;
void test1()
{
try
{
throw nullptr;
assert(false);
}
catch (md2 p)
{
assert(!p);
}
catch (md1)
{
assert(false);
}
}
void test2()
{
try
{
throw nullptr;
assert(false);
}
catch (md1 p)
{
assert(!p);
}
catch (md2)
{
assert(false);
}
}
#else
void test1()
{
}
void test2()
{
}
#endif
int main(int, char**)
{
test1();
test2();
return 0;
}

View file

@ -0,0 +1,149 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// 1b00fc5d8133 made it in the dylib in macOS 10.11
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10}}
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/cstdio"
#include "third_party/libcxx/cstdlib"
// Roll our own assertion macro to get better error messages out of the tests.
// In particular on systems that don't use __PRETTY_FUNCTION__ in assertions.
#define my_assert(pred, msg) do_assert(pred, msg, __LINE__, __PRETTY_FUNCTION__)
void do_assert(bool assert_passed, const char* msg, int line, const char* func) {
if (assert_passed)
return;
std::printf("%s:%d %s: Assertion Failed '%s'\n\n", __FILE__, line, func, msg);
std::abort();
}
struct A {};
struct Base {};
struct Derived : public Base {};
template <class To>
bool test_conversion(To) { return true; }
template <class To>
bool test_conversion(...) { return false; }
template <class Pointer>
struct CreatePointer {
Pointer operator()() const {
return (Pointer)0;
}
};
template <class Tp>
struct CreatePointer<Tp*> {
Tp* operator()() const {
return (Tp*)42;
}
};
template <class Throw, class Catch>
void catch_pointer_test() {
Throw throw_ptr = CreatePointer<Throw>()();
// Use the compiler to determine if the exception of type Throw can be
// implicitly converted to type Catch.
const bool can_convert = test_conversion<Catch>(throw_ptr);
try {
throw throw_ptr;
assert(false);
} catch (Catch catch_ptr) {
Catch catch2 = CreatePointer<Catch>()();
my_assert(can_convert, "non-convertible type incorrectly caught");
my_assert(catch_ptr == catch2,
"Thrown pointer does not match caught ptr");
} catch (...) {
my_assert(!can_convert, "convertible type incorrectly not caught");
}
}
// Generate CV qualified pointer typedefs.
template <class Tp, bool First = false>
struct TestTypes {
typedef Tp* Type;
typedef Tp const* CType;
typedef Tp volatile* VType;
typedef Tp const volatile* CVType;
};
// Special case for cv-qualifying a pointer-to-member without adding an extra
// pointer to it.
template <class Member, class Class>
struct TestTypes<Member Class::*, true> {
typedef Member (Class::*Type);
typedef const Member (Class::*CType);
typedef volatile Member (Class::*VType);
typedef const volatile Member (Class::*CVType);
};
template <class Throw, class Catch, int level, bool first = false>
struct generate_tests_imp {
typedef TestTypes<Throw, first> ThrowTypes;
typedef TestTypes<Catch, first> CatchTypes;
void operator()() {
typedef typename ThrowTypes::Type Type;
typedef typename ThrowTypes::CType CType;
typedef typename ThrowTypes::VType VType;
typedef typename ThrowTypes::CVType CVType;
run_catch_tests<Type>();
run_catch_tests<CType>();
run_catch_tests<VType>();
run_catch_tests<CVType>();
}
template <class ThrowTp>
void run_catch_tests() {
typedef typename CatchTypes::Type Type;
typedef typename CatchTypes::CType CType;
typedef typename CatchTypes::VType VType;
typedef typename CatchTypes::CVType CVType;
catch_pointer_test<ThrowTp, Type>();
catch_pointer_test<ThrowTp, CType>();
catch_pointer_test<ThrowTp, VType>();
catch_pointer_test<ThrowTp, CVType>();
generate_tests_imp<ThrowTp, Type, level-1>()();
generate_tests_imp<ThrowTp, CType, level-1>()();
generate_tests_imp<ThrowTp, VType, level-1>()();
generate_tests_imp<ThrowTp, CVType, level-1>()();
}
};
template <class Throw, class Catch, bool first>
struct generate_tests_imp<Throw, Catch, 0, first> {
void operator()() {
catch_pointer_test<Throw, Catch>();
}
};
template <class Throw, class Catch, int level>
struct generate_tests : generate_tests_imp<Throw, Catch, level, true> {};
int main(int, char**)
{
generate_tests<int, int, 3>()();
generate_tests<Base, Derived, 2>()();
generate_tests<Derived, Base, 2>()();
generate_tests<int, void, 2>()();
generate_tests<void, int, 2>()();
generate_tests<int A::*, int A::*, 3>()();
generate_tests<int A::*, void, 2>()();
generate_tests<void, int A::*, 2>()();
return 0;
}

View file

@ -0,0 +1,81 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Catching an exception thrown as nullptr was not properly handled before
// 2f984cab4fa7, which landed in macOS 10.13
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11|12}}
// UNSUPPORTED: c++03
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/cstdlib"
struct A {};
void test1()
{
try
{
throw nullptr;
assert(false);
}
catch (int* p)
{
assert(!p);
}
catch (long*)
{
assert(false);
}
}
void test2()
{
try
{
throw nullptr;
assert(false);
}
catch (A* p)
{
assert(!p);
}
catch (int*)
{
assert(false);
}
}
template <class Catch>
void catch_nullptr_test() {
try {
throw nullptr;
assert(false);
} catch (Catch c) {
assert(!c);
} catch (...) {
assert(false);
}
}
int main(int, char**)
{
// catch naked nullptrs
test1();
test2();
catch_nullptr_test<int*>();
catch_nullptr_test<int**>();
catch_nullptr_test<int A::*>();
catch_nullptr_test<const int A::*>();
catch_nullptr_test<int A::**>();
return 0;
}

View file

@ -0,0 +1,447 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This test case checks specifically the cases under bullet 3.1 & 3.2:
//
// C++ ABI 15.3:
// A handler is a match for an exception object of type E if
// * The handler is of type cv T or cv T& and E and T are the same type
// (ignoring the top-level cv-qualifiers), or
// * the handler is of type cv T or cv T& and T is an unambiguous base
// class of E, or
// > * the handler is of type cv1 T* cv2 and E is a pointer type that can <
// > be converted to the type of the handler by either or both of <
// > o a standard pointer conversion (4.10 [conv.ptr]) not involving <
// > conversions to private or protected or ambiguous classes <
// > o a qualification conversion <
// * the handler is a pointer or pointer to member type and E is
// std::nullptr_t
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/exception"
#include "libc/isystem/stdlib.h"
#include "libc/isystem/assert.h"
#include "libc/isystem/stdio.h"
struct Base {};
struct Derived : Base {};
struct Derived2 : Base {};
struct Ambiguous : Derived, Derived2 {};
struct Private : private Base {};
struct Protected : protected Base {};
template <typename T // Handler type
,typename E // Thrown exception type
,typename O // Object type
>
void assert_catches()
{
try
{
O o;
throw static_cast<E>(&o);
printf("%s\n", __PRETTY_FUNCTION__);
assert(false && "Statements after throw must be unreachable");
}
catch (T t)
{
assert(true);
return;
}
catch (...)
{
printf("%s\n", __PRETTY_FUNCTION__);
assert(false && "Should not have entered catch-all");
}
printf("%s\n", __PRETTY_FUNCTION__);
assert(false && "The catch should have returned");
}
template <typename T // Handler type
,typename E // Thrown exception type
,typename O // Object type
>
void assert_cannot_catch()
{
try
{
O o;
throw static_cast<E>(&o);
printf("%s\n", __PRETTY_FUNCTION__);
assert(false && "Statements after throw must be unreachable");
}
catch (T t)
{
printf("%s\n", __PRETTY_FUNCTION__);
assert(false && "Should not have entered the catch");
}
catch (...)
{
assert(true);
return;
}
printf("%s\n", __PRETTY_FUNCTION__);
assert(false && "The catch-all should have returned");
}
void f1()
{
// Test that every combination of handler of type:
// cv1 Base * cv2
// catches an exception of type:
// Derived *
assert_catches< Base * , Derived *, Derived>();
assert_catches<const Base * , Derived *, Derived>();
assert_catches< volatile Base * , Derived *, Derived>();
assert_catches<const volatile Base * , Derived *, Derived>();
assert_catches< Base * const , Derived *, Derived>();
assert_catches<const Base * const , Derived *, Derived>();
assert_catches< volatile Base * const , Derived *, Derived>();
assert_catches<const volatile Base * const , Derived *, Derived>();
assert_catches< Base * volatile, Derived *, Derived>();
assert_catches<const Base * volatile, Derived *, Derived>();
assert_catches< volatile Base * volatile, Derived *, Derived>();
assert_catches<const volatile Base * volatile, Derived *, Derived>();
assert_catches< Base * const volatile, Derived *, Derived>();
assert_catches<const Base * const volatile, Derived *, Derived>();
assert_catches< volatile Base * const volatile, Derived *, Derived>();
assert_catches<const volatile Base * const volatile, Derived *, Derived>();
}
void f2()
{
// Test that every combination of handler of type:
// cv1 Base * cv2
// catches an exception of type:
// Base *
assert_catches< Base * , Base *, Derived>();
assert_catches<const Base * , Base *, Derived>();
assert_catches< volatile Base * , Base *, Derived>();
assert_catches<const volatile Base * , Base *, Derived>();
assert_catches< Base * const , Base *, Derived>();
assert_catches<const Base * const , Base *, Derived>();
assert_catches< volatile Base * const , Base *, Derived>();
assert_catches<const volatile Base * const , Base *, Derived>();
assert_catches< Base * volatile, Base *, Derived>();
assert_catches<const Base * volatile, Base *, Derived>();
assert_catches< volatile Base * volatile, Base *, Derived>();
assert_catches<const volatile Base * volatile, Base *, Derived>();
assert_catches< Base * const volatile, Base *, Derived>();
assert_catches<const Base * const volatile, Base *, Derived>();
assert_catches< volatile Base * const volatile, Base *, Derived>();
assert_catches<const volatile Base * const volatile, Base *, Derived>();
}
void f3()
{
// Test that every combination of handler of type:
// cv1 Derived * cv2
// catches an exception of type:
// Derived *
assert_catches< Derived * , Derived *, Derived>();
assert_catches<const Derived * , Derived *, Derived>();
assert_catches< volatile Derived * , Derived *, Derived>();
assert_catches<const volatile Derived * , Derived *, Derived>();
assert_catches< Derived * const , Derived *, Derived>();
assert_catches<const Derived * const , Derived *, Derived>();
assert_catches< volatile Derived * const , Derived *, Derived>();
assert_catches<const volatile Derived * const , Derived *, Derived>();
assert_catches< Derived * volatile, Derived *, Derived>();
assert_catches<const Derived * volatile, Derived *, Derived>();
assert_catches< volatile Derived * volatile, Derived *, Derived>();
assert_catches<const volatile Derived * volatile, Derived *, Derived>();
assert_catches< Derived * const volatile, Derived *, Derived>();
assert_catches<const Derived * const volatile, Derived *, Derived>();
assert_catches< volatile Derived * const volatile, Derived *, Derived>();
assert_catches<const volatile Derived * const volatile, Derived *, Derived>();
}
void f4()
{
// Test that every combination of handler of type:
// cv1 Derived * cv2
// cannot catch an exception of type:
// Base *
assert_cannot_catch< Derived * , Base *, Derived>();
assert_cannot_catch<const Derived * , Base *, Derived>();
assert_cannot_catch< volatile Derived * , Base *, Derived>();
assert_cannot_catch<const volatile Derived * , Base *, Derived>();
assert_cannot_catch< Derived * const , Base *, Derived>();
assert_cannot_catch<const Derived * const , Base *, Derived>();
assert_cannot_catch< volatile Derived * const , Base *, Derived>();
assert_cannot_catch<const volatile Derived * const , Base *, Derived>();
assert_cannot_catch< Derived * volatile, Base *, Derived>();
assert_cannot_catch<const Derived * volatile, Base *, Derived>();
assert_cannot_catch< volatile Derived * volatile, Base *, Derived>();
assert_cannot_catch<const volatile Derived * volatile, Base *, Derived>();
assert_cannot_catch< Derived * const volatile, Base *, Derived>();
assert_cannot_catch<const Derived * const volatile, Base *, Derived>();
assert_cannot_catch< volatile Derived * const volatile, Base *, Derived>();
assert_cannot_catch<const volatile Derived * const volatile, Base *, Derived>();
}
void f5()
{
// Test that every combination of handler of type:
// cv1 Derived * cv2 &
// catches an exception of type:
// Derived *
assert_catches< Derived * &, Derived *, Derived>();
assert_catches<const Derived * &, Derived *, Derived>();
assert_catches< volatile Derived * &, Derived *, Derived>();
assert_catches<const volatile Derived * &, Derived *, Derived>();
assert_catches< Derived * const &, Derived *, Derived>();
assert_catches<const Derived * const &, Derived *, Derived>();
assert_catches< volatile Derived * const &, Derived *, Derived>();
assert_catches<const volatile Derived * const &, Derived *, Derived>();
assert_catches< Derived * volatile &, Derived *, Derived>();
assert_catches<const Derived * volatile &, Derived *, Derived>();
assert_catches< volatile Derived * volatile &, Derived *, Derived>();
assert_catches<const volatile Derived * volatile &, Derived *, Derived>();
assert_catches< Derived * const volatile &, Derived *, Derived>();
assert_catches<const Derived * const volatile &, Derived *, Derived>();
assert_catches< volatile Derived * const volatile &, Derived *, Derived>();
assert_catches<const volatile Derived * const volatile &, Derived *, Derived>();
}
void f6()
{
// Test that every combination of handler of type:
// cv1 Base * cv2 &
// catches an exception of type:
// Base *
assert_catches< Base * &, Base *, Derived>();
assert_catches<const Base * &, Base *, Derived>();
assert_catches< volatile Base * &, Base *, Derived>();
assert_catches<const volatile Base * &, Base *, Derived>();
assert_catches< Base * const &, Base *, Derived>();
assert_catches<const Base * const &, Base *, Derived>();
assert_catches< volatile Base * const &, Base *, Derived>();
assert_catches<const volatile Base * const &, Base *, Derived>();
assert_catches< Base * volatile &, Base *, Derived>();
assert_catches<const Base * volatile &, Base *, Derived>();
assert_catches< volatile Base * volatile &, Base *, Derived>();
assert_catches<const volatile Base * volatile &, Base *, Derived>();
assert_catches< Base * const volatile &, Base *, Derived>();
assert_catches<const Base * const volatile &, Base *, Derived>();
assert_catches< volatile Base * const volatile &, Base *, Derived>();
assert_catches<const volatile Base * const volatile &, Base *, Derived>();
}
void f7()
{
// Test that every combination of handler of type:
// cv1 Derived * cv2 &
// cannot catch an exception of type:
// Base *
assert_cannot_catch< Derived * &, Base *, Derived>();
assert_cannot_catch<const Derived * &, Base *, Derived>();
assert_cannot_catch< volatile Derived * &, Base *, Derived>();
assert_cannot_catch<const volatile Derived * &, Base *, Derived>();
assert_cannot_catch< Derived * const &, Base *, Derived>();
assert_cannot_catch<const Derived * const &, Base *, Derived>();
assert_cannot_catch< volatile Derived * const &, Base *, Derived>();
assert_cannot_catch<const volatile Derived * const &, Base *, Derived>();
assert_cannot_catch< Derived * volatile &, Base *, Derived>();
assert_cannot_catch<const Derived * volatile &, Base *, Derived>();
assert_cannot_catch< volatile Derived * volatile &, Base *, Derived>();
assert_cannot_catch<const volatile Derived * volatile &, Base *, Derived>();
assert_cannot_catch< Derived * const volatile &, Base *, Derived>();
assert_cannot_catch<const Derived * const volatile &, Base *, Derived>();
assert_cannot_catch< volatile Derived * const volatile &, Base *, Derived>();
assert_cannot_catch<const volatile Derived * const volatile &, Base *, Derived>();
}
void f8()
{
// This test case has a caveat noted in the discussion here:
// https://gcc.gnu.org/ml/gcc-patches/2009-08/msg00264.html
// Specifically:
// This [test exposes a] corner case of the ARM C++ ABI. The generic C++
// ABI also gets this wrong, because I failed to notice the subtlety here.
// The issue is that 15.3/3 3rd bullet says:
// The handler is of type cv1 T* cv2 and E is a pointer type that
// can be converted to the type of the handler by either or both of:
// * a standard pointer conversion (4.10) not involving conversions
// to pointers to private or protected or ambiguous classes
// Notice that the handlers of type "cv1 T*cv2&" are not allowed such
// freedom to find a base class. The ABI error is that we treat handlers
// of reference type exactly the same as the corresponding hander of
// non-reference type. Elsewhere in the exception handling this makes no
// difference (for instance bullet 1 explicitly says 'cv T or cv T&').
//
// See also: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#388
//
// TL;DR: it is an unresolved C++ ABI defect that these do catch
// Test that every combination of handler of type:
// cv1 Base * cv2 &
// catches an exception of type:
// Derived *
assert_catches< Base * &, Derived *, Derived>();
assert_catches<const Base * &, Derived *, Derived>();
assert_catches< volatile Base * &, Derived *, Derived>();
assert_catches<const volatile Base * &, Derived *, Derived>();
assert_catches< Base * const &, Derived *, Derived>();
assert_catches<const Base * const &, Derived *, Derived>();
assert_catches< volatile Base * const &, Derived *, Derived>();
assert_catches<const volatile Base * const &, Derived *, Derived>();
assert_catches< Base * volatile &, Derived *, Derived>();
assert_catches<const Base * volatile &, Derived *, Derived>();
assert_catches< volatile Base * volatile &, Derived *, Derived>();
assert_catches<const volatile Base * volatile &, Derived *, Derived>();
assert_catches< Base * const volatile &, Derived *, Derived>();
assert_catches<const Base * const volatile &, Derived *, Derived>();
assert_catches< volatile Base * const volatile &, Derived *, Derived>();
assert_catches<const volatile Base * const volatile &, Derived *, Derived>();
}
void f9()
{
// Test that every combination of handler of type:
// cv1 Base * cv2
// cannot catch an exception of type:
// Ambiguous *
assert_cannot_catch< Base * , Ambiguous *, Ambiguous>();
assert_cannot_catch<const Base * , Ambiguous *, Ambiguous>();
assert_cannot_catch< volatile Base * , Ambiguous *, Ambiguous>();
assert_cannot_catch<const volatile Base * , Ambiguous *, Ambiguous>();
assert_cannot_catch< Base * const , Ambiguous *, Ambiguous>();
assert_cannot_catch<const Base * const , Ambiguous *, Ambiguous>();
assert_cannot_catch< volatile Base * const , Ambiguous *, Ambiguous>();
assert_cannot_catch<const volatile Base * const , Ambiguous *, Ambiguous>();
assert_cannot_catch< Base * volatile, Ambiguous *, Ambiguous>();
assert_cannot_catch<const Base * volatile, Ambiguous *, Ambiguous>();
assert_cannot_catch< volatile Base * volatile, Ambiguous *, Ambiguous>();
assert_cannot_catch<const volatile Base * volatile, Ambiguous *, Ambiguous>();
assert_cannot_catch< Base * const volatile, Ambiguous *, Ambiguous>();
assert_cannot_catch<const Base * const volatile, Ambiguous *, Ambiguous>();
assert_cannot_catch< volatile Base * const volatile, Ambiguous *, Ambiguous>();
assert_cannot_catch<const volatile Base * const volatile, Ambiguous *, Ambiguous>();
}
void f10()
{
// Test that every combination of handler of type:
// cv1 Base * cv2
// cannot catch an exception of type:
// Private *
assert_cannot_catch< Base * , Private *, Private>();
assert_cannot_catch<const Base * , Private *, Private>();
assert_cannot_catch< volatile Base * , Private *, Private>();
assert_cannot_catch<const volatile Base * , Private *, Private>();
assert_cannot_catch< Base * const , Private *, Private>();
assert_cannot_catch<const Base * const , Private *, Private>();
assert_cannot_catch< volatile Base * const , Private *, Private>();
assert_cannot_catch<const volatile Base * const , Private *, Private>();
assert_cannot_catch< Base * volatile, Private *, Private>();
assert_cannot_catch<const Base * volatile, Private *, Private>();
assert_cannot_catch< volatile Base * volatile, Private *, Private>();
assert_cannot_catch<const volatile Base * volatile, Private *, Private>();
assert_cannot_catch< Base * const volatile, Private *, Private>();
assert_cannot_catch<const Base * const volatile, Private *, Private>();
assert_cannot_catch< volatile Base * const volatile, Private *, Private>();
assert_cannot_catch<const volatile Base * const volatile, Private *, Private>();
}
void f11()
{
// Test that every combination of handler of type:
// cv1 Base * cv2
// cannot catch an exception of type:
// Protected *
assert_cannot_catch< Base * , Protected *, Protected>();
assert_cannot_catch<const Base * , Protected *, Protected>();
assert_cannot_catch< volatile Base * , Protected *, Protected>();
assert_cannot_catch<const volatile Base * , Protected *, Protected>();
assert_cannot_catch< Base * const , Protected *, Protected>();
assert_cannot_catch<const Base * const , Protected *, Protected>();
assert_cannot_catch< volatile Base * const , Protected *, Protected>();
assert_cannot_catch<const volatile Base * const , Protected *, Protected>();
assert_cannot_catch< Base * volatile, Protected *, Protected>();
assert_cannot_catch<const Base * volatile, Protected *, Protected>();
assert_cannot_catch< volatile Base * volatile, Protected *, Protected>();
assert_cannot_catch<const volatile Base * volatile, Protected *, Protected>();
assert_cannot_catch< Base * const volatile, Protected *, Protected>();
assert_cannot_catch<const Base * const volatile, Protected *, Protected>();
assert_cannot_catch< volatile Base * const volatile, Protected *, Protected>();
assert_cannot_catch<const volatile Base * const volatile, Protected *, Protected>();
}
void f12()
{
// Test that every combination of handler of type:
// cv1 Base * cv2 &
// cannot catch an exception of type:
// Private *
assert_cannot_catch< Base * &, Private *, Private>();
assert_cannot_catch<const Base * &, Private *, Private>();
assert_cannot_catch< volatile Base * &, Private *, Private>();
assert_cannot_catch<const volatile Base * &, Private *, Private>();
assert_cannot_catch< Base * const &, Private *, Private>();
assert_cannot_catch<const Base * const &, Private *, Private>();
assert_cannot_catch< volatile Base * const &, Private *, Private>();
assert_cannot_catch<const volatile Base * const &, Private *, Private>();
assert_cannot_catch< Base * volatile &, Private *, Private>();
assert_cannot_catch<const Base * volatile &, Private *, Private>();
assert_cannot_catch< volatile Base * volatile &, Private *, Private>();
assert_cannot_catch<const volatile Base * volatile &, Private *, Private>();
assert_cannot_catch< Base * const volatile &, Private *, Private>();
assert_cannot_catch<const Base * const volatile &, Private *, Private>();
assert_cannot_catch< volatile Base * const volatile &, Private *, Private>();
assert_cannot_catch<const volatile Base * const volatile &, Private *, Private>();
}
void f13()
{
// Test that every combination of handler of type:
// cv1 Base * cv2 &
// cannot catch an exception of type:
// Protected *
assert_cannot_catch< Base * &, Protected *, Protected>();
assert_cannot_catch<const Base * &, Protected *, Protected>();
assert_cannot_catch< volatile Base * &, Protected *, Protected>();
assert_cannot_catch<const volatile Base * &, Protected *, Protected>();
assert_cannot_catch< Base * const &, Protected *, Protected>();
assert_cannot_catch<const Base * const &, Protected *, Protected>();
assert_cannot_catch< volatile Base * const &, Protected *, Protected>();
assert_cannot_catch<const volatile Base * const &, Protected *, Protected>();
assert_cannot_catch< Base * volatile &, Protected *, Protected>();
assert_cannot_catch<const Base * volatile &, Protected *, Protected>();
assert_cannot_catch< volatile Base * volatile &, Protected *, Protected>();
assert_cannot_catch<const volatile Base * volatile &, Protected *, Protected>();
assert_cannot_catch< Base * const volatile &, Protected *, Protected>();
assert_cannot_catch<const Base * const volatile &, Protected *, Protected>();
assert_cannot_catch< volatile Base * const volatile &, Protected *, Protected>();
assert_cannot_catch<const volatile Base * const volatile &, Protected *, Protected>();
}
int main(int, char**)
{
f1();
f2();
f3();
f4();
f5();
f6();
f7();
f8();
f9();
f10();
f11();
f12();
f13();
return 0;
}

View file

@ -0,0 +1,189 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/*
This test checks that adjustedPtr is correct as there exist offsets in this
object for the various subobjects, all of which have a unique id_ to
check against. It also checks that virtual bases work properly
*/
// UNSUPPORTED: no-exceptions
// Compilers emit warnings about exceptions of type 'Child' being caught by
// an earlier handler of type 'Base'. Congrats, you've just diagnosed the
// behavior under test.
// ADDITIONAL_COMPILE_FLAGS: -Wno-exceptions
#include "third_party/libcxx/exception"
#include "libc/isystem/stdlib.h"
#include "libc/isystem/assert.h"
struct B
{
static int count;
int id_;
explicit B(int id) : id_(id) {count++;}
B(const B& a) : id_(a.id_) {count++;}
~B() {count--;}
};
int B::count = 0;
struct C1
: virtual B
{
static int count;
int id_;
explicit C1(int id) : B(id-2), id_(id) {count++;}
C1(const C1& a) : B(a.id_-2), id_(a.id_) {count++;}
~C1() {count--;}
};
int C1::count = 0;
struct C2
: virtual private B
{
static int count;
int id_;
explicit C2(int id) : B(id-2), id_(id) {count++;}
C2(const C2& a) : B(a.id_-2), id_(a.id_) {count++;}
~C2() {count--;}
};
int C2::count = 0;
struct A
: C1, C2
{
static int count;
int id_;
explicit A(int id) : B(id+3), C1(id-1), C2(id-2), id_(id) {count++;}
A(const A& a) : B(a.id_+3), C1(a.id_-1), C2(a.id_-2), id_(a.id_) {count++;}
~A() {count--;}
};
int A::count = 0;
A global_a(5);
void f1()
{
throw &global_a;
assert(false);
}
void f2()
{
try
{
f1();
assert(false);
}
catch (const A* a) // can catch A
{
assert(a->id_ == 5);
assert(static_cast<const C1*>(a)->id_ == 4);
assert(static_cast<const C2*>(a)->id_ == 3);
assert(static_cast<const B*>(a)->id_ == 8);
throw;
}
catch (const C1*)
{
assert(false);
}
catch (const C2*)
{
assert(false);
}
catch (const B*)
{
assert(false);
}
}
void f3()
{
try
{
f2();
assert(false);
}
catch (const B* a) // can catch B
{
assert(static_cast<const B*>(a)->id_ == 8);
throw;
}
catch (const C1* c1)
{
assert(false);
}
catch (const C2*)
{
assert(false);
}
}
void f4()
{
try
{
f3();
assert(false);
}
catch (const C2* c2) // can catch C2
{
assert(c2->id_ == 3);
throw;
}
catch (const B* a)
{
assert(false);
}
catch (const C1*)
{
assert(false);
}
}
void f5()
{
try
{
f4();
assert(false);
}
catch (const C1* c1) // can catch C1
{
assert(c1->id_ == 4);
assert(static_cast<const B*>(c1)->id_ == 8);
throw;
}
catch (const B* a)
{
assert(false);
}
catch (const C2*)
{
assert(false);
}
}
int main(int, char**)
{
try
{
f5();
assert(false);
}
catch (...)
{
}
return 0;
}

View file

@ -0,0 +1,217 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// Compilers emit warnings about exceptions of type 'Child' being caught by
// an earlier handler of type 'Base'. Congrats, you've just diagnosed the
// behavior under test.
// ADDITIONAL_COMPILE_FLAGS: -Wno-exceptions
// The fix for PR17222 made it in the dylib for macOS 10.10
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.9
#include "third_party/libcxx/cassert"
#include "libc/isystem/stdint.h"
#if __cplusplus < 201103L
#define DISABLE_NULLPTR_TESTS
#endif
struct A {};
A a;
const A ca = A();
void test1 ()
{
try
{
throw &a;
assert(false);
}
catch ( const A* )
{
}
catch ( A *)
{
assert (false);
}
}
void test2 ()
{
try
{
throw &a;
assert(false);
}
catch ( A* )
{
}
catch ( const A *)
{
assert (false);
}
}
void test3 ()
{
try
{
throw &ca;
assert(false);
}
catch ( const A* )
{
}
catch ( A *)
{
assert (false);
}
}
void test4 ()
{
try
{
throw &ca;
assert(false);
}
catch ( A *)
{
assert (false);
}
catch ( const A* )
{
}
}
struct base1 {int x;};
struct base2 {int x;};
struct derived : base1, base2 {};
void test5 ()
{
try
{
throw (derived*)0;
assert(false);
}
catch (base2 *p) {
assert (p == 0);
}
catch (...)
{
assert (false);
}
}
void test6 ()
{
#if !defined(DISABLE_NULLPTR_TESTS)
try
{
throw nullptr;
assert(false);
}
catch (base2 *p) {
assert (p == nullptr);
}
catch (...)
{
assert (false);
}
#endif
}
void test7 ()
{
try
{
throw (derived*)12;
assert(false);
}
catch (base2 *p) {
assert ((uintptr_t)p == 12+sizeof(base1));
}
catch (...)
{
assert (false);
}
}
struct vBase {};
struct vDerived : virtual public vBase {};
void test8 ()
{
vDerived derived;
try
{
throw &derived;
assert(false);
}
catch (vBase *p) {
assert(p != 0);
}
catch (...)
{
assert (false);
}
}
void test9 ()
{
#if !defined(DISABLE_NULLPTR_TESTS)
try
{
throw nullptr;
assert(false);
}
catch (vBase *p) {
assert(p == 0);
}
catch (...)
{
assert (false);
}
#endif
}
void test10 ()
{
try
{
throw (vDerived*)0;
assert(false);
}
catch (vBase *p) {
assert(p == 0);
}
catch (...)
{
assert (false);
}
}
int main(int, char**)
{
test1();
test2();
test3();
test4();
test5();
test6();
test7();
test8();
test9();
test10();
return 0;
}

View file

@ -0,0 +1,53 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/cstddef"
#include "third_party/libcxx/cstdlib"
#include "third_party/libcxx/type_traits"
struct A {};
template<typename T, bool CanCatchNullptr>
static void catch_nullptr_test() {
try {
throw nullptr;
} catch (T &p) {
assert(CanCatchNullptr && !static_cast<bool>(p));
} catch (...) {
assert(!CanCatchNullptr);
}
}
int main(int, char**)
{
static_assert(std::is_same<std::nullptr_t, decltype(nullptr)>::value, "");
// A reference to nullptr_t can catch nullptr.
catch_nullptr_test<std::nullptr_t, true>();
catch_nullptr_test<const std::nullptr_t, true>();
catch_nullptr_test<volatile std::nullptr_t, true>();
catch_nullptr_test<const volatile std::nullptr_t, true>();
// No other reference type can.
#if 0
// FIXME: These tests fail, because the ABI provides no way for us to
// distinguish this from catching by value.
catch_nullptr_test<void *, false>();
catch_nullptr_test<void * const, false>();
catch_nullptr_test<int *, false>();
catch_nullptr_test<A *, false>();
catch_nullptr_test<int A::*, false>();
catch_nullptr_test<int (A::*)(), false>();
#endif
return 0;
}

View file

@ -0,0 +1,57 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/cassert"
#include "libc/isystem/stdlib.h"
#include "third_party/libcxx/exception"
#include "third_party/libcxx/typeinfo"
#include "third_party/libcxxabi/libcxx/test/support/test_macros.hh"
class Base {
virtual void foo() {};
};
class Derived : public Base {};
Derived &test_bad_cast(Base& b) {
return dynamic_cast<Derived&>(b);
}
Base gB;
void my_terminate() { exit(0); }
int main ()
{
// swap-out the terminate handler
void (*default_handler)() = std::get_terminate();
std::set_terminate(my_terminate);
#ifndef TEST_HAS_NO_EXCEPTIONS
try {
#endif
Derived &d = test_bad_cast(gB);
assert(false);
((void)d);
#ifndef TEST_HAS_NO_EXCEPTIONS
} catch (std::bad_cast const&) {
// success
return 0;
} catch (...) {
assert(false);
}
#endif
// failure, restore the default terminate handler and fire
std::set_terminate(default_handler);
std::terminate();
}

View file

@ -0,0 +1,55 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===------------------------------------------------------------------------===//
// UNSUPPORTED: c++03
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/cassert"
#include "libc/isystem/stdlib.h"
#include "third_party/libcxx/exception"
#include "third_party/libcxx/typeinfo"
#include "third_party/libcxx/string"
#include "third_party/libcxxabi/libcxx/test/support/test_macros.hh"
class Base {
virtual void foo() {};
};
class Derived : public Base {};
std::string test_bad_typeid(Derived *p) {
return typeid(*p).name();
}
void my_terminate() { exit(0); }
int main ()
{
// swap-out the terminate handler
void (*default_handler)() = std::get_terminate();
std::set_terminate(my_terminate);
#ifndef TEST_HAS_NO_EXCEPTIONS
try {
#endif
test_bad_typeid(nullptr);
assert(false);
#ifndef TEST_HAS_NO_EXCEPTIONS
} catch (std::bad_typeid const&) {
// success
return 0;
} catch (...) {
assert(false);
}
#endif
// failure, restore the default terminate handler and fire
std::set_terminate(default_handler);
std::terminate();
}

View file

@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-threads
// REQUIRES: linux
#include "libc/isystem/assert.h"
#include "third_party/libcxxabi/include/cxxabi.h"
static bool AtexitImplCalled = false;
extern "C" int __cxa_thread_atexit_impl(void (*dtor)(void *), void *obj,
void *dso_symbol) {
assert(dtor == reinterpret_cast<void (*)(void *)>(1));
assert(obj == reinterpret_cast<void *>(2));
assert(dso_symbol == reinterpret_cast<void *>(3));
AtexitImplCalled = true;
return 4;
}
int main(int, char**) {
int RV = __cxxabiv1::__cxa_thread_atexit(
reinterpret_cast<void (*)(void *)>(1), reinterpret_cast<void *>(2),
reinterpret_cast<void *>(3));
assert(RV == 4);
assert(AtexitImplCalled);
return 0;
}

View file

@ -0,0 +1,125 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// PR41395 isn't fixed until the dylib shipped with macOS 10.15
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14}}
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/new"
#include "third_party/libcxx/cassert"
void dummy_ctor(void*) { assert(false && "should not be called"); }
void dummy_dtor(void*) { assert(false && "should not be called"); }
void *dummy_alloc(size_t) { assert(false && "should not be called"); return nullptr; }
void dummy_dealloc(void*) { assert(false && "should not be called"); }
void dummy_dealloc_sized(void*, size_t) { assert(false && "should not be called"); }
bool check_mul_overflows(size_t x, size_t y) {
size_t tmp = x * y;
if (tmp / x != y)
return true;
return false;
}
bool check_add_overflows(size_t x, size_t y) {
size_t tmp = x + y;
if (tmp < x)
return true;
return false;
}
void test_overflow_in_multiplication() {
const size_t elem_count = std::size_t(1) << (sizeof(std::size_t) * 8 - 2);
const size_t elem_size = 8;
const size_t padding = 0;
assert(check_mul_overflows(elem_count, elem_size));
try {
__cxxabiv1::__cxa_vec_new(elem_count, elem_size, padding, dummy_ctor,
dummy_dtor);
assert(false && "allocation should fail");
} catch (std::bad_array_new_length const&) {
// OK
} catch (...) {
assert(false && "unexpected exception");
}
try {
__cxxabiv1::__cxa_vec_new2(elem_count, elem_size, padding, dummy_ctor,
dummy_dtor, &dummy_alloc, &dummy_dealloc);
assert(false && "allocation should fail");
} catch (std::bad_array_new_length const&) {
// OK
} catch (...) {
assert(false && "unexpected exception");
}
try {
__cxxabiv1::__cxa_vec_new3(elem_count, elem_size, padding, dummy_ctor,
dummy_dtor, &dummy_alloc, &dummy_dealloc_sized);
assert(false && "allocation should fail");
} catch (std::bad_array_new_length const&) {
// OK
} catch (...) {
assert(false && "unexpected exception");
}
}
void test_overflow_in_addition() {
const size_t elem_size = 4;
const size_t elem_count = static_cast<size_t>(-1) / 4u;
#if defined(_LIBCXXABI_ARM_EHABI)
const size_t padding = 8;
#else
const size_t padding = sizeof(std::size_t);
#endif
assert(!check_mul_overflows(elem_count, elem_size));
assert(check_add_overflows(elem_count * elem_size, padding));
try {
__cxxabiv1::__cxa_vec_new(elem_count, elem_size, padding, dummy_ctor,
dummy_dtor);
assert(false && "allocation should fail");
} catch (std::bad_array_new_length const&) {
// OK
} catch (...) {
assert(false && "unexpected exception");
}
try {
__cxxabiv1::__cxa_vec_new2(elem_count, elem_size, padding, dummy_ctor,
dummy_dtor, &dummy_alloc, &dummy_dealloc);
assert(false && "allocation should fail");
} catch (std::bad_array_new_length const&) {
// OK
} catch (...) {
assert(false && "unexpected exception");
}
try {
__cxxabiv1::__cxa_vec_new3(elem_count, elem_size, padding, dummy_ctor,
dummy_dtor, &dummy_alloc, &dummy_dealloc_sized);
assert(false && "allocation should fail");
} catch (std::bad_array_new_length const&) {
// OK
} catch (...) {
assert(false && "unexpected exception");
}
}
int main(int, char**) {
test_overflow_in_multiplication();
test_overflow_in_addition();
return 0;
}

View file

@ -0,0 +1,163 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// PR33425 and PR33487 are not fixed until the dylib shipped with macOS 10.15
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.14
// PR33439 isn't fixed until the dylib shipped with macOS 10.14
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11|12|13}}
#include "third_party/libcxx/cassert"
// This test explicitly tests dynamic cast with types that have inaccessible
// bases.
#if defined(__clang__)
# pragma clang diagnostic ignored "-Winaccessible-base"
#elif defined(__GNUC__)
# pragma GCC diagnostic ignored "-Winaccessible-base"
#endif
typedef char Pad1[43981];
typedef char Pad2[34981];
typedef char Pad3[93481];
typedef char Pad4[13489];
typedef char Pad5[81349];
typedef char Pad6[34819];
typedef char Pad7[3489];
namespace t1
{
// PR33425
struct C3 { virtual ~C3() {} Pad1 _; };
struct C5 : protected virtual C3 { Pad2 _; };
struct C6 : virtual C5 { Pad3 _; };
struct C7 : virtual C3 { Pad4 _; };
struct C9 : C6, C7 { Pad5 _; };
C9 c9;
C3 *c3 = &c9;
void test()
{
assert(dynamic_cast<C3*>(c3) == static_cast<C3*>(&c9));
assert(dynamic_cast<C5*>(c3) == static_cast<C5*>(&c9));
assert(dynamic_cast<C6*>(c3) == static_cast<C6*>(&c9));
assert(dynamic_cast<C7*>(c3) == static_cast<C7*>(&c9));
assert(dynamic_cast<C9*>(c3) == static_cast<C9*>(&c9));
}
} // t1
namespace t2
{
// PR33425
struct Src { virtual ~Src() {} Pad1 _; };
struct Mask : protected virtual Src { Pad2 _; };
struct Dest : Mask { Pad3 _; };
struct Root : Dest, virtual Src { Pad4 _; };
Root root;
Src *src = &root;
void test()
{
assert(dynamic_cast<Src*>(src) == static_cast<Src*>(&root));
assert(dynamic_cast<Mask*>(src) == static_cast<Mask*>(&root));
assert(dynamic_cast<Dest*>(src) == static_cast<Dest*>(&root));
assert(dynamic_cast<Root*>(src) == static_cast<Root*>(&root));
}
} // t2
namespace t3
{
// PR33487
struct Class1 { virtual ~Class1() {} Pad1 _; };
struct Shared : virtual Class1 { Pad2 _; };
struct Class6 : virtual Shared { Pad3 _; };
struct Left : Class6 { Pad4 _; };
struct Right : Class6 { Pad5 _; };
struct Main : Left, Right { Pad6 _; };
Main m;
Class1 *c1 = &m;
void test()
{
assert(dynamic_cast<Class1*>(c1) == static_cast<Class1*>(&m));
assert(dynamic_cast<Shared*>(c1) == static_cast<Shared*>(&m));
assert(dynamic_cast<Class6*>(c1) == 0);
assert(dynamic_cast<Left*>(c1) == static_cast<Left*>(&m));
assert(dynamic_cast<Right*>(c1) == static_cast<Right*>(&m));
assert(dynamic_cast<Main*>(c1) == static_cast<Main*>(&m));
}
} // t3
namespace t4
{
// PR33439
struct C2 { virtual ~C2() {} Pad1 _; };
struct C3 { virtual ~C3() {} Pad2 _; };
struct C4 : C3 { Pad3 _; };
struct C8 : C2, virtual C4 { Pad4 _; };
struct C9 : C4, C8 { Pad5 _; };
C9 c9;
C2 *c2 = &c9;
void test()
{
assert(dynamic_cast<C2*>(c2) == static_cast<C2*>(&c9));
assert(dynamic_cast<C3*>(c2) == 0);
assert(dynamic_cast<C4*>(c2) == 0);
assert(dynamic_cast<C8*>(c2) == static_cast<C8*>(&c9));
assert(dynamic_cast<C9*>(c2) == static_cast<C9*>(&c9));
}
} // t4
namespace t5
{
// PR33439
struct Dummy { virtual ~Dummy() {} Pad1 _; };
struct Src { virtual ~Src() {} Pad2 _; };
struct Dest : Dummy { Pad3 _; };
struct A1 : Dest { Pad4 _; };
struct A2 : Dest { Pad5 _; };
struct Root : Src, A1, A2 { Pad6 _; };
Root root;
Src *src = &root;
void test()
{
assert(dynamic_cast<Dummy*>(src) == 0);
assert(dynamic_cast<Src*>(src) == static_cast<Src*>(&root));
assert(dynamic_cast<Dest*>(src) == 0);
assert(dynamic_cast<A1*>(src) == static_cast<A1*>(&root));
assert(dynamic_cast<A2*>(src) == static_cast<A2*>(&root));
}
} // t5
int main(int, char**)
{
t1::test();
t2::test();
t3::test();
t4::test();
t5::test();
return 0;
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,82 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/tuple"
#include "third_party/libcxxabi/test/support/timer.hh"
template <std::size_t Indx, std::size_t Depth>
struct C
: public virtual C<Indx, Depth-1>,
public virtual C<Indx+1, Depth-1>
{
virtual ~C() {}
};
template <std::size_t Indx>
struct C<Indx, 0>
{
virtual ~C() {}
};
template <std::size_t Indx, std::size_t Depth>
struct B
: public virtual C<Indx, Depth-1>,
public virtual C<Indx+1, Depth-1>
{
};
template <class Indx, std::size_t Depth>
struct makeB;
template <std::size_t ...Indx, std::size_t Depth>
struct makeB<std::__tuple_indices<Indx...>, Depth>
: public B<Indx, Depth>...
{
};
template <std::size_t Width, std::size_t Depth>
struct A
: public makeB<typename std::__make_tuple_indices<Width>::type, Depth>
{
};
void test()
{
const std::size_t Width = 10;
const std::size_t Depth = 5;
A<Width, Depth> a;
typedef B<Width/2, Depth> Destination;
// typedef A<Width, Depth> Destination;
Destination *b = nullptr;
{
timer t;
b = dynamic_cast<Destination*>((C<Width/2, 0>*)&a);
}
assert(b != 0);
}
int main(int, char**)
{
test();
return 0;
}
/*
Timing results I'm seeing (median of 3 microseconds):
libc++abi gcc's dynamic_cast
B<Width/2, Depth> -O3 48.334 93.190 libc++abi 93% faster
B<Width/2, Depth> -Os 58.535 94.103 libc++abi 61% faster
A<Width, Depth> -O3 11.515 33.134 libc++abi 188% faster
A<Width, Depth> -Os 12.631 31.553 libc++abi 150% faster
*/

View file

@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// This test checks that the compiler does not make incorrect assumptions
// about the alignment of the exception (only in that specific case, of
// course).
//
// There was a bug where Clang would emit a call to memset assuming a 16-byte
// aligned exception even when back-deploying to older Darwin systems where
// exceptions are 8-byte aligned, which caused a segfault on those systems.
struct exception {
exception() : x(0) { }
virtual ~exception() { }
int x;
};
struct foo : exception { };
int main(int, char**) {
try {
throw foo();
} catch (...) {
}
return 0;
}

View file

@ -0,0 +1,39 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// The situation for the alignment of exception objects is badly messed up
// before macOS 10.14. The test fails on macOS 10.9 to 10.12, passes on macOS
// 10.13 (no investigation done), and passes afterwards. Just mark all the OSes
// before 10.14 as unsupported.
// UNSUPPORTED: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11|12|13}}
// Check that the pointer __cxa_allocate_exception returns is aligned to the
// default alignment for the target architecture.
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/cstdint"
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/type_traits"
#include "third_party/libcxxabi/include/__cxxabi_config.h"
struct S {
int a[4];
} __attribute__((aligned));
int main(int, char**) {
#if !defined(_LIBCXXABI_ARM_EHABI)
void *p = __cxxabiv1::__cxa_allocate_exception(16);
auto i = reinterpret_cast<uintptr_t>(p);
auto a = std::alignment_of<S>::value;
assert(i % a == 0);
__cxxabiv1::__cxa_free_exception(p);
#endif
return 0;
}

View file

@ -0,0 +1,164 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// UNSUPPORTED: c++03
// Necessary because we include a private header of libc++abi, which
// only understands _LIBCXXABI_HAS_NO_THREADS.
#include "third_party/libcxxabi/libcxx/test/support/test_macros.hh"
#ifdef TEST_HAS_NO_THREADS
# define _LIBCXXABI_HAS_NO_THREADS
#endif
#define TESTING_CXA_GUARD
#include "third_party/libcxxabi/cxa_guard_impl.h"
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/type_traits"
#if defined(__clang__)
# pragma clang diagnostic ignored "-Wtautological-pointer-compare"
#elif defined(__GNUC__)
# pragma GCC diagnostic ignored "-Waddress"
#endif
using namespace __cxxabiv1;
template <class GuardType, class Impl>
struct Tests {
private:
Tests() : g{}, impl(&g) {}
GuardType g;
Impl impl;
uint8_t first_byte() {
uint8_t first;
std::memcpy(&first, &g, 1);
return first;
}
void reset() { g = {}; }
public:
// Test the post conditions on cxa_guard_acquire, cxa_guard_abort, and
// cxa_guard_release. Specifically, that they leave the first byte with
// the value 0 or 1 as specified by the ARM or Itanium specification.
static void test() {
Tests tests;
tests.test_acquire();
tests.test_abort();
tests.test_release();
}
void test_acquire() {
{
reset();
assert(first_byte() == 0);
assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
assert(first_byte() == 0);
}
{
reset();
assert(first_byte() == 0);
assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
impl.cxa_guard_release();
assert(first_byte() == 1);
assert(impl.cxa_guard_acquire() == INIT_IS_DONE);
}
}
void test_release() {
{
reset();
assert(first_byte() == 0);
assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
assert(first_byte() == 0);
impl.cxa_guard_release();
assert(first_byte() == 1);
}
}
void test_abort() {
{
reset();
assert(first_byte() == 0);
assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
assert(first_byte() == 0);
impl.cxa_guard_abort();
assert(first_byte() == 0);
assert(impl.cxa_guard_acquire() == INIT_IS_PENDING);
assert(first_byte() == 0);
}
}
};
struct NopMutex {
bool lock() {
assert(!is_locked);
is_locked = true;
return false;
}
bool unlock() {
assert(is_locked);
is_locked = false;
return false;
}
private:
bool is_locked = false;
};
NopMutex global_nop_mutex = {};
struct NopCondVar {
bool broadcast() { return false; }
bool wait(NopMutex&) { return false; }
};
NopCondVar global_nop_cond = {};
void NopFutexWait(int*, int) { assert(false); }
void NopFutexWake(int*) { assert(false); }
uint32_t MockGetThreadID() { return 0; }
int main(int, char**) {
{
#if defined(TEST_HAS_NO_THREADS)
static_assert(CurrentImplementation == Implementation::NoThreads, "");
static_assert(std::is_same<SelectedImplementation, NoThreadsGuard>::value, "");
#else
static_assert(CurrentImplementation == Implementation::GlobalMutex, "");
static_assert(std::is_same<SelectedImplementation,
GlobalMutexGuard<LibcppMutex, LibcppCondVar, GlobalStatic<LibcppMutex>::instance,
GlobalStatic<LibcppCondVar>::instance>>::value,
"");
#endif
}
{
#if (defined(__APPLE__) || defined(__linux__)) && !defined(TEST_HAS_NO_THREADS)
assert(PlatformThreadID);
#endif
if (PlatformThreadID != nullptr) {
assert(PlatformThreadID() != 0);
assert(PlatformThreadID() == PlatformThreadID());
}
}
{
Tests<uint32_t, NoThreadsGuard>::test();
Tests<uint64_t, NoThreadsGuard>::test();
}
{
using MutexImpl = GlobalMutexGuard<NopMutex, NopCondVar, global_nop_mutex, global_nop_cond, MockGetThreadID>;
Tests<uint32_t, MutexImpl>::test();
Tests<uint64_t, MutexImpl>::test();
}
{
using FutexImpl = FutexGuard<&NopFutexWait, &NopFutexWake, &MockGetThreadID>;
Tests<uint32_t, FutexImpl>::test();
Tests<uint64_t, FutexImpl>::test();
}
return 0;
}

View file

@ -0,0 +1,386 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03
// UNSUPPORTED: no-threads
// UNSUPPORTED: no-exceptions
#define TESTING_CXA_GUARD
#include "third_party/libcxxabi/cxa_guard_impl.h"
#include "third_party/libcxx/unordered_map"
#include "third_party/libcxx/thread"
#include "third_party/libcxx/atomic"
#include "third_party/libcxx/array"
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/memory"
#include "third_party/libcxx/vector"
#include "third_party/libcxxabi/libcxx/test/support/make_test_thread.hh"
#include "third_party/libcxxabi/libcxx/test/support/test_macros.hh"
using namespace __cxxabiv1;
// Misc test configuration. It's used to tune the flakyness of the test.
// ThreadsPerTest - The number of threads used
constexpr int ThreadsPerTest = 10;
// The number of instances of a test to run concurrently.
constexpr int ConcurrentRunsPerTest = 10;
// The number of times to rerun each test.
constexpr int TestSamples = 50;
void BusyWait() {
std::this_thread::yield();
}
void YieldAfterBarrier() {
std::this_thread::sleep_for(std::chrono::nanoseconds(10));
std::this_thread::yield();
}
struct Barrier {
explicit Barrier(int n) : m_threads(n), m_remaining(n) { }
Barrier(Barrier const&) = delete;
Barrier& operator=(Barrier const&) = delete;
void arrive_and_wait() const {
--m_remaining;
while (m_remaining.load()) {
BusyWait();
}
}
void arrive_and_drop() const {
--m_remaining;
}
void wait_for_threads(int n) const {
while ((m_threads - m_remaining.load()) < n) {
std::this_thread::yield();
}
}
private:
const int m_threads;
mutable std::atomic<int> m_remaining;
};
enum class InitResult {
COMPLETE,
PERFORMED,
WAITED,
ABORTED
};
constexpr InitResult COMPLETE = InitResult::COMPLETE;
constexpr InitResult PERFORMED = InitResult::PERFORMED;
constexpr InitResult WAITED = InitResult::WAITED;
constexpr InitResult ABORTED = InitResult::ABORTED;
template <class Impl, class GuardType, class Init>
InitResult check_guard(GuardType *g, Init init) {
uint8_t *first_byte = reinterpret_cast<uint8_t*>(g);
if (std::__libcpp_atomic_load(first_byte, std::_AO_Acquire) == 0) {
Impl impl(g);
if (impl.cxa_guard_acquire() == INIT_IS_PENDING) {
#ifndef TEST_HAS_NO_EXCEPTIONS
try {
#endif
init();
impl.cxa_guard_release();
return PERFORMED;
#ifndef TEST_HAS_NO_EXCEPTIONS
} catch (...) {
impl.cxa_guard_abort();
return ABORTED;
}
#endif
}
return WAITED;
}
return COMPLETE;
}
template <class GuardType, class Impl>
struct FunctionLocalStatic {
FunctionLocalStatic() {}
FunctionLocalStatic(FunctionLocalStatic const&) = delete;
template <class InitFunc>
InitResult access(InitFunc&& init) {
auto res = check_guard<Impl>(&guard_object, init);
++result_counts[static_cast<int>(res)];
return res;
}
template <class InitFn>
struct AccessCallback {
void operator()() const { this_obj->access(init); }
FunctionLocalStatic *this_obj;
InitFn init;
};
template <class InitFn, class Callback = AccessCallback< InitFn > >
Callback access_callback(InitFn init) {
return Callback{this, init};
}
int get_count(InitResult I) const {
return result_counts[static_cast<int>(I)].load();
}
int num_completed() const {
return get_count(COMPLETE) + get_count(PERFORMED) + get_count(WAITED);
}
int num_waiting() const {
return waiting_threads.load();
}
private:
GuardType guard_object = {};
std::atomic<int> waiting_threads{0};
std::array<std::atomic<int>, 4> result_counts{};
static_assert(static_cast<int>(ABORTED) == 3, "only 4 result kinds expected");
};
struct ThreadGroup {
ThreadGroup() = default;
ThreadGroup(ThreadGroup const&) = delete;
template <class ...Args>
void Create(Args&& ...args) {
threads.emplace_back(std::forward<Args>(args)...);
}
template <class Callback>
void CreateThreadsWithBarrier(int N, Callback cb) {
auto start = std::make_shared<Barrier>(N + 1);
for (int I=0; I < N; ++I) {
Create([start, cb]() {
start->arrive_and_wait();
cb();
});
}
start->arrive_and_wait();
}
void JoinAll() {
for (auto& t : threads) {
t.join();
}
}
private:
std::vector<std::thread> threads;
};
template <class GuardType, class Impl>
void test_free_for_all(int num_waiters) {
FunctionLocalStatic<GuardType, Impl> test_obj;
ThreadGroup threads;
bool already_init = false;
threads.CreateThreadsWithBarrier(num_waiters,
test_obj.access_callback([&]() {
assert(!already_init);
already_init = true;
})
);
// wait for the other threads to finish initialization.
threads.JoinAll();
assert(test_obj.get_count(PERFORMED) == 1);
assert(test_obj.get_count(COMPLETE) + test_obj.get_count(WAITED) == num_waiters - 1);
}
template <class GuardType, class Impl>
void test_waiting_for_init(int num_waiters) {
FunctionLocalStatic<GuardType, Impl> test_obj;
ThreadGroup threads;
Barrier start_init(2);
threads.Create(test_obj.access_callback(
[&]() {
start_init.arrive_and_wait();
// Take our sweet time completing the initialization...
//
// There's a race condition between the other threads reaching the
// start_init barrier, and them actually hitting the cxa guard.
// But we're trying to test the waiting logic, we want as many
// threads to enter the waiting loop as possible.
YieldAfterBarrier();
}
));
start_init.wait_for_threads(1);
threads.CreateThreadsWithBarrier(num_waiters,
test_obj.access_callback([]() { assert(false); })
);
// unblock the initializing thread
start_init.arrive_and_drop();
// wait for the other threads to finish initialization.
threads.JoinAll();
assert(test_obj.get_count(PERFORMED) == 1);
assert(test_obj.get_count(ABORTED) == 0);
assert(test_obj.get_count(COMPLETE) + test_obj.get_count(WAITED) == num_waiters);
}
template <class GuardType, class Impl>
void test_aborted_init(int num_waiters) {
FunctionLocalStatic<GuardType, Impl> test_obj;
Barrier start_init(2);
ThreadGroup threads;
threads.Create(test_obj.access_callback(
[&]() {
start_init.arrive_and_wait();
YieldAfterBarrier();
throw 42;
})
);
start_init.wait_for_threads(1);
bool already_init = false;
threads.CreateThreadsWithBarrier(num_waiters,
test_obj.access_callback([&]() {
assert(!already_init);
already_init = true;
})
);
// unblock the initializing thread
start_init.arrive_and_drop();
// wait for the other threads to finish initialization.
threads.JoinAll();
assert(test_obj.get_count(ABORTED) == 1);
assert(test_obj.get_count(PERFORMED) == 1);
assert(test_obj.get_count(WAITED) + test_obj.get_count(COMPLETE) == num_waiters - 1);
}
template <class GuardType, class Impl>
void test_completed_init(int num_waiters) {
FunctionLocalStatic<GuardType, Impl> test_obj;
test_obj.access([]() {}); // initialize the object
assert(test_obj.num_waiting() == 0);
assert(test_obj.num_completed() == 1);
assert(test_obj.get_count(PERFORMED) == 1);
ThreadGroup threads;
threads.CreateThreadsWithBarrier(num_waiters,
test_obj.access_callback([]() { assert(false); })
);
// wait for the other threads to finish initialization.
threads.JoinAll();
assert(test_obj.get_count(ABORTED) == 0);
assert(test_obj.get_count(PERFORMED) == 1);
assert(test_obj.get_count(WAITED) == 0);
assert(test_obj.get_count(COMPLETE) == num_waiters);
}
template <class Impl>
void test_impl() {
using TestFn = void(*)(int);
TestFn TestList[] = {
test_free_for_all<uint32_t, Impl>,
test_free_for_all<uint32_t, Impl>,
test_waiting_for_init<uint32_t, Impl>,
test_waiting_for_init<uint64_t, Impl>,
test_aborted_init<uint32_t, Impl>,
test_aborted_init<uint64_t, Impl>,
test_completed_init<uint32_t, Impl>,
test_completed_init<uint64_t, Impl>
};
for (auto test_func : TestList) {
ThreadGroup test_threads;
test_threads.CreateThreadsWithBarrier(ConcurrentRunsPerTest, [=]() {
for (int I = 0; I < TestSamples; ++I) {
test_func(ThreadsPerTest);
}
});
test_threads.JoinAll();
}
}
void test_all_impls() {
using MutexImpl = SelectImplementation<Implementation::GlobalMutex>::type;
// Attempt to test the Futex based implementation if it's supported on the
// target platform.
using RealFutexImpl = SelectImplementation<Implementation::Futex>::type;
using FutexImpl = typename std::conditional<
PlatformSupportsFutex(),
RealFutexImpl,
MutexImpl
>::type;
test_impl<MutexImpl>();
if (PlatformSupportsFutex())
test_impl<FutexImpl>();
}
// A dummy
template <bool Dummy = true>
void test_futex_syscall() {
if (!PlatformSupportsFutex())
return;
int lock1 = 0;
int lock2 = 0;
int lock3 = 0;
std::thread waiter1 = support::make_test_thread([&]() {
int expect = 0;
PlatformFutexWait(&lock1, expect);
assert(lock1 == 1);
});
std::thread waiter2 = support::make_test_thread([&]() {
int expect = 0;
PlatformFutexWait(&lock2, expect);
assert(lock2 == 2);
});
std::thread waiter3 = support::make_test_thread([&]() {
int expect = 42; // not the value
PlatformFutexWait(&lock3, expect); // doesn't block
});
std::thread waker = support::make_test_thread([&]() {
lock1 = 1;
PlatformFutexWake(&lock1);
lock2 = 2;
PlatformFutexWake(&lock2);
});
waiter1.join();
waiter2.join();
waiter3.join();
waker.join();
}
int main(int, char**) {
// Test each multi-threaded implementation with real threads.
test_all_impls();
// Test the basic sanity of the futex syscall wrappers.
test_futex_syscall();
return 0;
}

View file

@ -0,0 +1,211 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#rtti-layout
// Two abi::__pbase_type_info objects can always be compared for equality
// (i.e. of the types represented) or ordering by comparison of their name
// NTBS addresses. In addition, unless either or both have either of the
// incomplete flags set, equality can be tested by comparing the type_info
// addresses.
// UNSUPPORTED: no-exceptions
// UNSUPPORTED: no-rtti
// The fix for PR25898 landed in the system dylibs in macOS 10.13
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11|12}}
// RUN: %{cxx} %{flags} %{compile_flags} -Wno-unreachable-code -c %s -o %t.one.o
// RUN: %{cxx} %{flags} %{compile_flags} -Wno-unreachable-code -c %s -o %t.two.o -DTU_ONE
// RUN: %{cxx} %{flags} %t.one.o %t.two.o %{link_flags} -o %t.exe
// RUN: %{exec} %t.exe
#include "libc/stdio/stdio.h"
#include "third_party/libcxx/cstring"
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/typeinfo"
// Check that the addresses of the typeinfo differ but still compare equal
// via their NTBS.
inline void
AssertIncompleteTypeInfoEquals(std::type_info const& LHS, std::type_info const& RHS)
{
assert(&LHS != &RHS);
assert(strcmp(LHS.name(), RHS.name()) == 0);
}
struct NeverDefined;
void ThrowNeverDefinedMP();
std::type_info const& ReturnTypeInfoNeverDefinedMP();
struct IncompleteAtThrow;
void ThrowIncompleteMP();
void ThrowIncompletePP();
void ThrowIncompletePMP();
std::type_info const& ReturnTypeInfoIncompleteMP();
std::type_info const& ReturnTypeInfoIncompletePP();
struct CompleteAtThrow;
void ThrowCompleteMP();
void ThrowCompletePP();
void ThrowCompletePMP();
std::type_info const& ReturnTypeInfoCompleteMP();
std::type_info const& ReturnTypeInfoCompletePP();
void ThrowNullptr();
#ifndef TU_ONE
void ThrowNeverDefinedMP() { throw (int NeverDefined::*)nullptr; }
std::type_info const& ReturnTypeInfoNeverDefinedMP() { return typeid(int NeverDefined::*); }
void ThrowIncompleteMP() { throw (int IncompleteAtThrow::*)nullptr; }
void ThrowIncompletePP() { throw (IncompleteAtThrow**)nullptr; }
void ThrowIncompletePMP() { throw (int IncompleteAtThrow::**)nullptr; }
std::type_info const& ReturnTypeInfoIncompleteMP() { return typeid(int IncompleteAtThrow::*); }
std::type_info const& ReturnTypeInfoIncompletePP() { return typeid(IncompleteAtThrow**); }
struct CompleteAtThrow {};
void ThrowCompleteMP() { throw (int CompleteAtThrow::*)nullptr; }
void ThrowCompletePP() { throw (CompleteAtThrow**)nullptr; }
void ThrowCompletePMP() { throw (int CompleteAtThrow::**)nullptr; }
std::type_info const& ReturnTypeInfoCompleteMP() { return typeid(int CompleteAtThrow::*); }
std::type_info const& ReturnTypeInfoCompletePP() { return typeid(CompleteAtThrow**); }
void ThrowNullptr() { throw nullptr; }
#else
struct IncompleteAtThrow {};
int main(int, char**) {
AssertIncompleteTypeInfoEquals(ReturnTypeInfoNeverDefinedMP(), typeid(int NeverDefined::*));
try {
ThrowNeverDefinedMP();
assert(false);
} catch (int IncompleteAtThrow::*) {
assert(false);
} catch (int CompleteAtThrow::*) {
assert(false);
} catch (int NeverDefined::*p) {
assert(!p);
}
catch(...) { assert(!"FAIL: Didn't catch NeverDefined::*" ); }
AssertIncompleteTypeInfoEquals(ReturnTypeInfoIncompleteMP(), typeid(int IncompleteAtThrow::*));
try {
ThrowIncompleteMP();
assert(false);
} catch (CompleteAtThrow**) {
assert(false);
} catch (int CompleteAtThrow::*) {
assert(false);
} catch (IncompleteAtThrow**) {
assert(false);
} catch (int IncompleteAtThrow::*p) {
assert(!p);
}
catch(...) { assert(!"FAIL: Didn't catch IncompleteAtThrow::*" ); }
AssertIncompleteTypeInfoEquals(ReturnTypeInfoIncompletePP(), typeid(IncompleteAtThrow**));
try {
ThrowIncompletePP();
assert(false);
} catch (int IncompleteAtThrow::*) {
assert(false);
} catch (IncompleteAtThrow** p) {
assert(!p);
}
catch(...) { assert(!"FAIL: Didn't catch IncompleteAtThrow**" ); }
try {
ThrowIncompletePMP();
assert(false);
} catch (int IncompleteAtThrow::*) {
assert(false);
} catch (IncompleteAtThrow**) {
assert(false);
} catch (int IncompleteAtThrow::**p) {
assert(!p);
}
catch(...) { assert(!"FAIL: Didn't catch IncompleteAtThrow::**" ); }
AssertIncompleteTypeInfoEquals(ReturnTypeInfoCompleteMP(), typeid(int CompleteAtThrow::*));
try {
ThrowCompleteMP();
assert(false);
} catch (IncompleteAtThrow**) {
assert(false);
} catch (int IncompleteAtThrow::*) {
assert(false);
} catch (CompleteAtThrow**) {
assert(false);
} catch (int CompleteAtThrow::*p) {
assert(!p);
}
catch(...) { assert(!"FAIL: Didn't catch CompleteAtThrow::" ); }
AssertIncompleteTypeInfoEquals(ReturnTypeInfoCompletePP(), typeid(CompleteAtThrow**));
try {
ThrowCompletePP();
assert(false);
} catch (IncompleteAtThrow**) {
assert(false);
} catch (int IncompleteAtThrow::*) {
assert(false);
} catch (int CompleteAtThrow::*) {
assert(false);
} catch (CompleteAtThrow**p) {
assert(!p);
}
catch(...) { assert(!"FAIL: Didn't catch CompleteAtThrow**" ); }
try {
ThrowCompletePMP();
assert(false);
} catch (IncompleteAtThrow**) {
assert(false);
} catch (int IncompleteAtThrow::*) {
assert(false);
} catch (int CompleteAtThrow::*) {
assert(false);
} catch (CompleteAtThrow**) {
assert(false);
} catch (int CompleteAtThrow::**p) {
assert(!p);
}
catch(...) { assert(!"FAIL: Didn't catch CompleteAtThrow::**" ); }
#if __cplusplus >= 201103L
// Catch nullptr as complete type
try {
ThrowNullptr();
} catch (int IncompleteAtThrow::*p) {
assert(!p);
}
catch(...) { assert(!"FAIL: Didn't catch nullptr as IncompleteAtThrow::*" ); }
// Catch nullptr as an incomplete type
try {
ThrowNullptr();
} catch (int CompleteAtThrow::*p) {
assert(!p);
}
catch(...) { assert(!"FAIL: Didn't catch nullptr as CompleteAtThrow::*" ); }
// Catch nullptr as a type that is never complete.
try {
ThrowNullptr();
} catch (int NeverDefined::*p) {
assert(!p);
}
catch(...) { assert(!"FAIL: Didn't catch nullptr as NeverDefined::*" ); }
#endif
return 0;
}
#endif

View file

@ -0,0 +1 @@
incomplete_type.sh.cc

View file

@ -0,0 +1 @@
incomplete_type.sh.cc

View file

@ -0,0 +1,173 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This test case checks specifically the cases under C++ ABI 15.3.1, and 15.3.2
//
// C++ ABI 15.3:
// A handler is a match for an exception object of type E if
// > * The handler is of type cv T or cv T& and E and T are the same type <
// > (ignoring the top-level cv-qualifiers), or <
// > * the handler is of type cv T or cv T& and T is an unambiguous base <
// > class of E, or <
// * the handler is of type cv1 T* cv2 and E is a pointer type that can
// be converted to the type of the handler by either or both of
// o a standard pointer conversion (4.10 [conv.ptr]) not involving
// conversions to private or protected or ambiguous classes
// o a qualification conversion
// * the handler is a pointer or pointer to member type and E is
// std::nullptr_t
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// Compilers emit warnings about exceptions of type 'Child' being caught by
// an earlier handler of type 'Base'. Congrats, you've just diagnosed the
// behavior under test.
// ADDITIONAL_COMPILE_FLAGS: -Wno-exceptions
#include "libc/isystem/assert.h"
struct Base {
int b1;
};
struct Base2 {
int b2;
};
struct Child : public Base, public Base2 {
int c;
};
void f1() {
Child child;
child.b1 = 10;
child.b2 = 11;
child.c = 12;
throw child;
}
void f2() {
Child child;
child.b1 = 10;
child.b2 = 11;
child.c = 12;
throw static_cast<Base2&>(child);
}
void f3() {
static Child child;
child.b1 = 10;
child.b2 = 11;
child.c = 12;
throw static_cast<Base2*>(&child);
}
int main(int, char**)
{
try
{
f1();
assert(false);
}
catch (const Child& c)
{
assert(true);
}
catch (const Base& b)
{
assert(false);
}
catch (...)
{
assert(false);
}
try
{
f1();
assert(false);
}
catch (const Base& c)
{
assert(true);
}
catch (const Child& b)
{
assert(false);
}
catch (...)
{
assert(false);
}
try
{
f1();
assert(false);
}
catch (const Base2& c)
{
assert(true);
}
catch (const Child& b)
{
assert(false);
}
catch (...)
{
assert(false);
}
try
{
f2();
assert(false);
}
catch (const Child& c)
{
assert(false);
}
catch (const Base& b)
{
assert(false);
}
catch (const Base2& b)
{
assert(true);
}
catch (...)
{
assert(false);
}
try
{
f3();
assert(false);
}
catch (const Base* c)
{
assert(false);
}
catch (const Child* b)
{
assert(false);
}
catch (const Base2* c)
{
assert(true);
}
catch (...)
{
assert(false);
}
return 0;
}

View file

@ -0,0 +1,54 @@
//===----------------------------------------------------------------------===////
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===////
#ifndef TIMER_H
#define TIMER_H
// Define LIBCXXABI_USE_TIMER to enable testing with a timer.
#if defined(LIBCXXABI_USE_TIMER)
#include "third_party/libcxx/chrono"
#include "third_party/libcxx/cstdio"
class timer
{
typedef std::chrono::high_resolution_clock Clock;
typedef Clock::time_point TimePoint;
typedef std::chrono::microseconds MicroSeconds;
public:
timer() : m_start(Clock::now()) {}
timer(timer const &) = delete;
timer & operator=(timer const &) = delete;
~timer()
{
using std::chrono::duration_cast;
TimePoint end = Clock::now();
MicroSeconds us = duration_cast<MicroSeconds>(end - m_start);
std::printf("%d microseconds\n", us.count());
}
private:
TimePoint m_start;
};
#else /* LIBCXXABI_USE_TIMER */
class timer
{
public:
timer() {}
timer(timer const &) = delete;
timer & operator=(timer const &) = delete;
~timer() {}
};
#endif /* LIBCXXABI_USE_TIMER */
#endif /* TIMER_H */

View file

@ -0,0 +1,62 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/typeinfo"
// Test taken from 5.2.8.2
// When typeid is applied to a glvalue expression whose type is a polymorphic
// class type, (10.3), the result refers to a std::type_info object
// representing the type of the most derived object (1.8) (that is, the
// dynamic type) to which the glvalue refers. If the glvalue expression is
// obtained by applying the unary * operator to a pointer(68) and the pointer
// is a null pointer value (4.10), the typeid expression throws the
// std::bad_typeid exception (18.7.3).
//
// 68) If p is an expression of pointer type, then *p, (*p), *(p),
// ((*p)), *((p)), and so on all meet this requirement.
bool bad_typeid_test () {
class A { virtual void f() {}};
class B { virtual void g() {}};
B *bp = NULL;
try {bool b = typeid(*bp) == typeid (A); ((void)b); }
catch ( const std::bad_typeid &) { return true; }
return false;
}
// The value of a failed cast to pointer type is the null pointer value of
// the required result type. A failed cast to reference type throws
// std::bad_cast (18.7.2).
bool bad_cast_test () {
class A { virtual void f() {}};
class B { virtual void g() {}};
class D : public virtual A, private B {};
D d;
B *bp = (B*)&d; // cast needed to break protection
try { D &dr = dynamic_cast<D&> (*bp); ((void)dr); }
catch ( const std::bad_cast & ) { return true; }
return false;
}
int main ( ) {
int ret_val = 0;
if ( !bad_typeid_test ()) {
ret_val = 1;
}
if ( !bad_cast_test ()) {
ret_val = 2;
}
return ret_val;
}

View file

@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// ___cxa_throw_bad_array_new_length is re-exported from libc++ only starting
// in macosx 10.15
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14}}
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/new"
// If the expression passed to operator new[] would result in an overflow, the
// allocation function is not called, and a std::bad_array_new_length exception
// is thrown instead (5.3.4p7).
bool bad_array_new_length_test() {
try {
// We test this directly because Clang does not currently codegen the
// correct call to __cxa_bad_array_new_length, so this test would result
// in passing -1 to ::operator new[], which would then throw a
// std::bad_alloc, causing the test to fail.
__cxxabiv1::__cxa_throw_bad_array_new_length();
} catch ( const std::bad_array_new_length &banl ) {
return true;
}
return false;
}
int main(int, char**) {
int ret_val = 0;
if ( !bad_array_new_length_test ()) {
ret_val = 1;
}
return ret_val;
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,53 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// UNSUPPORTED: c++03
// The <unwind.h> header provided in the SDK of older Xcodes used to provide
// an incorrectly aligned _Unwind_Exception type on non-ARM. That causes these
// tests to fail when running against a system libc++abi and libunwind that was
// compiled with an incorrect definition of _Unwind_Exception.
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11|12}}
// Test that the address of the exception object is properly aligned as required
// by the relevant ABI
#include "third_party/libcxx/cstdint"
#include "third_party/libcxx/cassert"
#include "third_party/libcxxabi/include/__cxxabi_config.h"
#include "third_party/libunwind/include/unwind.h"
struct __attribute__((aligned)) AlignedType {};
// EHABI : 8-byte aligned
// Itanium: Largest supported alignment for the system
#if defined(_LIBCXXABI_ARM_EHABI)
# define EXPECTED_ALIGNMENT 8
#else
# define EXPECTED_ALIGNMENT alignof(AlignedType)
#endif
static_assert(alignof(_Unwind_Exception) == EXPECTED_ALIGNMENT,
"_Unwind_Exception is incorrectly aligned. This test is expected to fail");
struct MinAligned { };
static_assert(alignof(MinAligned) == 1 && sizeof(MinAligned) == 1, "");
int main(int, char**) {
for (int i=0; i < 10; ++i) {
try {
throw MinAligned{};
} catch (MinAligned const& ref) {
assert(reinterpret_cast<uintptr_t>(&ref) % EXPECTED_ALIGNMENT == 0);
}
}
return 0;
}

View file

@ -0,0 +1,76 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "third_party/libcxx/algorithm"
#include "third_party/libcxx/cstdio"
#include "third_party/libcxx/cstdlib"
#include "third_party/libcxx/__threading_support"
#include "libc/isystem/unistd.h"
#include "third_party/libcxxabi/cxa_exception.h"
#include "third_party/libcxxabi/libcxx/test/support/test_macros.hh"
typedef __cxxabiv1::__cxa_eh_globals globals_t ;
void *thread_code (void *parm) {
size_t *result = (size_t *) parm;
globals_t *glob1, *glob2;
glob1 = __cxxabiv1::__cxa_get_globals ();
if ( NULL == glob1 )
std::printf("Got null result from __cxa_get_globals\n");
glob2 = __cxxabiv1::__cxa_get_globals_fast ();
if ( glob1 != glob2 )
std::printf("Got different globals!\n");
*result = (size_t) glob1;
#ifndef TEST_HAS_NO_THREADS
sleep ( 1 );
#endif
return parm;
}
#ifndef TEST_HAS_NO_THREADS
#define NUMTHREADS 10
size_t thread_globals [ NUMTHREADS ] = { 0 };
std::__libcpp_thread_t threads [ NUMTHREADS ];
#endif
int main() {
#ifndef TEST_HAS_NO_THREADS
// Make the threads, let them run, and wait for them to finish
for ( int i = 0; i < NUMTHREADS; ++i )
std::__libcpp_thread_create ( threads + i, thread_code, (void *) (thread_globals + i));
for ( int i = 0; i < NUMTHREADS; ++i )
std::__libcpp_thread_join ( &threads [ i ] );
int retVal = 0;
for ( int i = 0; i < NUMTHREADS; ++i ) {
if ( 0 == thread_globals [ i ] ) {
std::printf("Thread #%d had a zero global\n", i);
retVal = 1;
}
}
std::sort ( thread_globals, thread_globals + NUMTHREADS );
for ( int i = 1; i < NUMTHREADS; ++i ) {
if ( thread_globals [ i - 1 ] == thread_globals [ i ] ) {
std::printf("Duplicate thread globals (%d and %d)\n", i-1, i);
retVal = 2;
}
}
return retVal;
#else // TEST_HAS_NO_THREADS
size_t thread_globals;
thread_code(&thread_globals);
// Check that __cxa_get_globals() is not NULL.
return (thread_globals == 0) ? 1 : 0;
#endif // !TEST_HAS_NO_THREADS
}

View file

@ -0,0 +1,212 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "third_party/libcxx/cstdio"
#include "third_party/libcxx/deque"
#include "third_party/libcxx/cassert"
#include "libc/isystem/inttypes.h"
#include "third_party/libcxx/__threading_support"
// UNSUPPORTED: c++03
// UNSUPPORTED: modules-build && no-threads
// Necessary because we include a private source file of libc++abi, which
// only understands _LIBCXXABI_HAS_NO_THREADS.
#include "third_party/libcxxabi/libcxx/test/support/test_macros.hh"
#ifdef TEST_HAS_NO_THREADS
# define _LIBCXXABI_HAS_NO_THREADS
#endif
typedef std::deque<void *> container;
TEST_DIAGNOSTIC_PUSH
TEST_CLANG_DIAGNOSTIC_IGNORED("-Wprivate-header")
// #define DEBUG_FALLBACK_MALLOC
#define INSTRUMENT_FALLBACK_MALLOC
#include "third_party/libcxxabi/fallback_malloc.cc"
TEST_DIAGNOSTIC_POP
void assertAlignment(void* ptr) { assert(reinterpret_cast<size_t>(ptr) % alignof(FallbackMaxAlignType) == 0); }
container alloc_series ( size_t sz ) {
container ptrs;
void *p;
while (NULL != (p = fallback_malloc(sz))) {
assertAlignment(p);
ptrs.push_back(p);
}
return ptrs;
}
container alloc_series ( size_t sz, float growth ) {
container ptrs;
void *p;
while ( NULL != ( p = fallback_malloc ( sz ))) {
assertAlignment(p);
ptrs.push_back(p);
sz *= growth;
}
return ptrs;
}
container alloc_series ( const size_t *first, size_t len ) {
container ptrs;
const size_t *last = first + len;
void * p;
for ( const size_t *iter = first; iter != last; ++iter ) {
if ( NULL == (p = fallback_malloc ( *iter )))
break;
assertAlignment(p);
ptrs.push_back ( p );
}
return ptrs;
}
void *pop ( container &c, bool from_end ) {
void *ptr;
if ( from_end ) {
ptr = c.back ();
c.pop_back ();
}
else {
ptr = c.front ();
c.pop_front ();
}
return ptr;
}
void exhaustion_test1 () {
container ptrs;
init_heap ();
std::printf("Constant exhaustion tests\n");
// Delete in allocation order
ptrs = alloc_series ( 32 );
std::printf("Allocated %zu 32 byte chunks\n", ptrs.size());
print_free_list ();
for ( container::iterator iter = ptrs.begin (); iter != ptrs.end (); ++iter )
fallback_free ( *iter );
print_free_list ();
std::printf("----\n");
// Delete in reverse order
ptrs = alloc_series ( 32 );
std::printf("Allocated %zu 32 byte chunks\n", ptrs.size());
for ( container::reverse_iterator iter = ptrs.rbegin (); iter != ptrs.rend (); ++iter )
fallback_free ( *iter );
print_free_list ();
std::printf("----\n");
// Alternate deletions
ptrs = alloc_series ( 32 );
std::printf("Allocated %zu 32 byte chunks\n", ptrs.size());
while ( ptrs.size () > 0 )
fallback_free ( pop ( ptrs, ptrs.size () % 1 == 1 ));
print_free_list ();
}
void exhaustion_test2 () {
container ptrs;
init_heap ();
std::printf("Growing exhaustion tests\n");
// Delete in allocation order
ptrs = alloc_series ( 32, 1.5 );
std::printf("Allocated %zu { 32, 48, 72, 108, 162 ... } byte chunks\n",
ptrs.size());
print_free_list ();
for ( container::iterator iter = ptrs.begin (); iter != ptrs.end (); ++iter )
fallback_free ( *iter );
print_free_list ();
std::printf("----\n");
// Delete in reverse order
print_free_list ();
ptrs = alloc_series ( 32, 1.5 );
std::printf("Allocated %zu { 32, 48, 72, 108, 162 ... } byte chunks\n",
ptrs.size());
for ( container::reverse_iterator iter = ptrs.rbegin (); iter != ptrs.rend (); ++iter )
fallback_free ( *iter );
print_free_list ();
std::printf("----\n");
// Alternate deletions
ptrs = alloc_series ( 32, 1.5 );
std::printf("Allocated %zu { 32, 48, 72, 108, 162 ... } byte chunks\n",
ptrs.size());
while ( ptrs.size () > 0 )
fallback_free ( pop ( ptrs, ptrs.size () % 1 == 1 ));
print_free_list ();
}
void exhaustion_test3 () {
const size_t allocs [] = { 124, 60, 252, 60, 4 };
container ptrs;
init_heap ();
std::printf("Complete exhaustion tests\n");
// Delete in allocation order
ptrs = alloc_series ( allocs, sizeof ( allocs ) / sizeof ( allocs[0] ));
std::printf("Allocated %zu chunks\n", ptrs.size());
print_free_list ();
for ( container::iterator iter = ptrs.begin (); iter != ptrs.end (); ++iter )
fallback_free ( *iter );
print_free_list ();
std::printf("----\n");
// Delete in reverse order
print_free_list ();
ptrs = alloc_series ( allocs, sizeof ( allocs ) / sizeof ( allocs[0] ));
std::printf("Allocated %zu chunks\n", ptrs.size());
for ( container::reverse_iterator iter = ptrs.rbegin (); iter != ptrs.rend (); ++iter )
fallback_free ( *iter );
print_free_list ();
std::printf("----\n");
// Alternate deletions
ptrs = alloc_series ( allocs, sizeof ( allocs ) / sizeof ( allocs[0] ));
std::printf("Allocated %zu chunks\n", ptrs.size());
while ( ptrs.size () > 0 )
fallback_free ( pop ( ptrs, ptrs.size () % 1 == 1 ));
print_free_list ();
}
int main () {
print_free_list ();
char *p = (char *) fallback_malloc ( 1024 ); // too big!
std::printf("fallback_malloc ( 1024 ) --> %" PRIuPTR"\n", (uintptr_t) p);
print_free_list ();
p = (char *) fallback_malloc ( 32 );
std::printf("fallback_malloc ( 32 ) --> %" PRIuPTR"\n", (uintptr_t) (p - heap));
if ( !is_fallback_ptr ( p ))
std::printf("### p is not a fallback pointer!!\n");
print_free_list ();
fallback_free ( p );
print_free_list ();
exhaustion_test1();
exhaustion_test2();
exhaustion_test3();
return 0;
}

View file

@ -0,0 +1,151 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "third_party/libcxx/cassert"
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxxabi/libcxx/test/support/test_macros.hh"
#ifndef TEST_HAS_NO_THREADS
# include "third_party/libcxx/thread"
# include "third_party/libcxxabi/libcxx/test/support/make_test_thread.hh"
#endif
// Ensure that we initialize each variable once and only once.
namespace test1 {
static int run_count = 0;
int increment() {
++run_count;
return 0;
}
void helper() {
static int a = increment();
((void)a);
}
void test() {
static int a = increment(); ((void)a);
assert(run_count == 1);
static int b = increment(); ((void)b);
assert(run_count == 2);
helper();
assert(run_count == 3);
helper();
assert(run_count == 3);
}
}
// When initialization fails, ensure that we try to initialize it again next
// time.
namespace test2 {
#ifndef TEST_HAS_NO_EXCEPTIONS
static int run_count = 0;
int increment() {
++run_count;
throw 0;
}
void helper() {
try {
static int a = increment();
assert(false);
((void)a);
} catch (...) {}
}
void test() {
helper();
assert(run_count == 1);
helper();
assert(run_count == 2);
}
#else
void test() {}
#endif
}
// Check that we can initialize a second value while initializing a first.
namespace test3 {
int zero() {
return 0;
}
int one() {
static int b = zero(); ((void)b);
return 0;
}
void test() {
static int a = one(); ((void)a);
}
}
#ifndef TEST_HAS_NO_THREADS
// A simple thread test of two threads racing to initialize a variable. This
// isn't guaranteed to catch any particular threading problems.
namespace test4 {
static int run_count = 0;
int increment() {
++run_count;
return 0;
}
void helper() {
static int a = increment(); ((void)a);
}
void test() {
std::thread t1 = support::make_test_thread(helper);
std::thread t2 = support::make_test_thread(helper);
t1.join();
t2.join();
assert(run_count == 1);
}
}
// Check that we don't re-initialize a static variable even when it's
// encountered from two different threads.
namespace test5 {
static int run_count = 0;
int zero() {
++run_count;
return 0;
}
int one() {
static int b = zero(); ((void)b);
return 0;
}
void another_helper() {
static int a = one(); ((void)a);
}
void helper() {
static int a = one(); ((void)a);
std::thread t = support::make_test_thread(another_helper);
t.join();
}
void test() {
std::thread t = support::make_test_thread(helper);
t.join();
assert(run_count == 1);
}
}
#endif /* TEST_HAS_NO_THREADS */
int main(int, char**)
{
test1::test();
test2::test();
test3::test();
#ifndef TEST_HAS_NO_THREADS
test4::test();
test5::test();
#endif
return 0;
}

View file

@ -0,0 +1,278 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/cstdio"
#include "third_party/libcxx/cstdlib"
#include "third_party/libcxxabi/libcxx/test/support/test_macros.hh"
// Wrapper routines
void *my_alloc2 ( size_t sz ) {
void *p = std::malloc ( sz );
// std::printf ( "Allocated %ld bytes at %lx\n", sz, (unsigned long) p );
return p;
}
void my_dealloc2 ( void *p ) {
// std::printf ( "Freeing %lx\n", (unsigned long) p );
std::free ( p );
}
void my_dealloc3 ( void *p, size_t ) {
// std::printf ( "Freeing %lx (size %ld)\n", (unsigned long) p, sz );
std::free ( p );
}
void my_construct ( void * ) {
// std::printf ( "Constructing %lx\n", (unsigned long) p );
}
void my_destruct ( void * ) {
// std::printf ( "Destructing %lx\n", (unsigned long) p );
}
int gCounter;
void count_construct ( void * ) { ++gCounter; }
void count_destruct ( void * ) { --gCounter; }
int gConstructorCounter;
int gConstructorThrowTarget;
int gDestructorCounter;
int gDestructorThrowTarget;
void throw_construct ( void * ) {
#ifndef TEST_HAS_NO_EXCEPTIONS
if ( gConstructorCounter == gConstructorThrowTarget )
throw 1;
++gConstructorCounter;
#endif
}
void throw_destruct ( void * ) {
#ifndef TEST_HAS_NO_EXCEPTIONS
if ( ++gDestructorCounter == gDestructorThrowTarget )
throw 2;
#endif
}
#if __cplusplus >= 201103L
# define CAN_THROW noexcept(false)
#else
# define CAN_THROW
#endif
struct vec_on_stack {
void *storage;
vec_on_stack () : storage ( __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct )) {}
~vec_on_stack () CAN_THROW {__cxxabiv1::__cxa_vec_delete ( storage, 40, 8, throw_destruct ); }
};
// Test calls with empty constructors and destructors
int test_empty ( ) {
void *one, *two, *three;
// Try with no padding and no con/destructors
one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, NULL, NULL );
two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, NULL, NULL, my_alloc2, my_dealloc2 );
three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, NULL, NULL, my_alloc2, my_dealloc3 );
__cxxabiv1::__cxa_vec_delete ( one, 40, 0, NULL );
__cxxabiv1::__cxa_vec_delete2( two, 40, 0, NULL, my_dealloc2 );
__cxxabiv1::__cxa_vec_delete3( three, 40, 0, NULL, my_dealloc3 );
// Try with no padding
one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, my_construct, my_destruct );
two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, my_construct, my_destruct, my_alloc2, my_dealloc2 );
three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, my_construct, my_destruct, my_alloc2, my_dealloc3 );
__cxxabiv1::__cxa_vec_delete ( one, 40, 0, my_destruct );
__cxxabiv1::__cxa_vec_delete2( two, 40, 0, my_destruct, my_dealloc2 );
__cxxabiv1::__cxa_vec_delete3( three, 40, 0, my_destruct, my_dealloc3 );
// Padding and no con/destructors
one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, NULL, NULL );
two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, NULL, NULL, my_alloc2, my_dealloc2 );
three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, NULL, NULL, my_alloc2, my_dealloc3 );
__cxxabiv1::__cxa_vec_delete ( one, 40, 8, NULL );
__cxxabiv1::__cxa_vec_delete2( two, 40, 8, NULL, my_dealloc2 );
__cxxabiv1::__cxa_vec_delete3( three, 40, 8, NULL, my_dealloc3 );
// Padding with con/destructors
one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, my_construct, my_destruct );
two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, my_construct, my_destruct, my_alloc2, my_dealloc2 );
three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, my_construct, my_destruct, my_alloc2, my_dealloc3 );
__cxxabiv1::__cxa_vec_delete ( one, 40, 8, my_destruct );
__cxxabiv1::__cxa_vec_delete2( two, 40, 8, my_destruct, my_dealloc2 );
__cxxabiv1::__cxa_vec_delete3( three, 40, 8, my_destruct, my_dealloc3 );
return 0;
}
// Make sure the constructors and destructors are matched
int test_counted ( ) {
int retVal = 0;
void *one, *two, *three;
// Try with no padding
gCounter = 0;
one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, count_construct, count_destruct );
two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, count_construct, count_destruct, my_alloc2, my_dealloc2 );
three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, count_construct, count_destruct, my_alloc2, my_dealloc3 );
__cxxabiv1::__cxa_vec_delete ( one, 40, 0, count_destruct );
__cxxabiv1::__cxa_vec_delete2( two, 40, 0, count_destruct, my_dealloc2 );
__cxxabiv1::__cxa_vec_delete3( three, 40, 0, count_destruct, my_dealloc3 );
// Since there was no padding, the # of elements in the array are not stored
// and the destructors are not called.
if ( gCounter != 30 ) {
std::printf("Mismatched Constructor/Destructor calls (1)\n");
std::printf(" Expected 30, got %d\n", gCounter);
retVal = 1;
}
gCounter = 0;
one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, count_construct, count_destruct );
two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, count_construct, count_destruct, my_alloc2, my_dealloc2 );
three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, count_construct, count_destruct, my_alloc2, my_dealloc3 );
__cxxabiv1::__cxa_vec_delete ( one, 40, 8, count_destruct );
__cxxabiv1::__cxa_vec_delete2( two, 40, 8, count_destruct, my_dealloc2 );
__cxxabiv1::__cxa_vec_delete3( three, 40, 8, count_destruct, my_dealloc3 );
if ( gCounter != 0 ) {
std::printf("Mismatched Constructor/Destructor calls (2)\n");
std::printf(" Expected 0, got %d\n", gCounter);
retVal = 1;
}
return retVal;
}
#ifndef TEST_HAS_NO_EXCEPTIONS
// Make sure the constructors and destructors are matched
int test_exception_in_constructor ( ) {
int retVal = 0;
void *one, *two, *three;
// Try with no padding
gConstructorCounter = gDestructorCounter = 0;
gConstructorThrowTarget = 15;
gDestructorThrowTarget = -1;
try {
one = two = three = NULL;
one = __cxxabiv1::__cxa_vec_new ( 10, 40, 0, throw_construct, throw_destruct );
two = __cxxabiv1::__cxa_vec_new2( 10, 40, 0, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
three = __cxxabiv1::__cxa_vec_new3( 10, 40, 0, throw_construct, throw_destruct, my_alloc2, my_dealloc3 );
}
catch ( int i ) {}
__cxxabiv1::__cxa_vec_delete ( one, 40, 0, throw_destruct );
__cxxabiv1::__cxa_vec_delete2( two, 40, 0, throw_destruct, my_dealloc2 );
__cxxabiv1::__cxa_vec_delete3( three, 40, 0, throw_destruct, my_dealloc3 );
// Since there was no padding, the # of elements in the array are not stored
// and the destructors are not called.
// Since we threw after 15 calls to the constructor, we should see 5 calls to
// the destructor from the partially constructed array.
if ( gConstructorCounter - gDestructorCounter != 10 ) {
std::printf("Mismatched Constructor/Destructor calls (1C)\n");
std::printf("%d constructors, but %d destructors\n", gConstructorCounter, gDestructorCounter);
retVal = 1;
}
gConstructorCounter = gDestructorCounter = 0;
gConstructorThrowTarget = 15;
gDestructorThrowTarget = -1;
try {
one = two = three = NULL;
one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct );
two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
three = __cxxabiv1::__cxa_vec_new3( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc3 );
}
catch ( int i ) {}
__cxxabiv1::__cxa_vec_delete ( one, 40, 8, throw_destruct );
__cxxabiv1::__cxa_vec_delete2( two, 40, 8, throw_destruct, my_dealloc2 );
__cxxabiv1::__cxa_vec_delete3( three, 40, 8, throw_destruct, my_dealloc3 );
if ( gConstructorCounter != gDestructorCounter ) {
std::printf("Mismatched Constructor/Destructor calls (2C)\n");
std::printf("%d constructors, but %d destructors\n", gConstructorCounter, gDestructorCounter);
retVal = 1;
}
return retVal;
}
#endif
#ifndef TEST_HAS_NO_EXCEPTIONS
// Make sure the constructors and destructors are matched
int test_exception_in_destructor ( ) {
int retVal = 0;
void *one, *two, *three;
one = two = three = NULL;
// Throw from within a destructor
gConstructorCounter = gDestructorCounter = 0;
gConstructorThrowTarget = -1;
gDestructorThrowTarget = 15;
try {
one = two = NULL;
one = __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct );
two = __cxxabiv1::__cxa_vec_new2( 10, 40, 8, throw_construct, throw_destruct, my_alloc2, my_dealloc2 );
}
catch ( int i ) {}
try {
__cxxabiv1::__cxa_vec_delete ( one, 40, 8, throw_destruct );
__cxxabiv1::__cxa_vec_delete2( two, 40, 8, throw_destruct, my_dealloc2 );
assert(false);
}
catch ( int i ) {}
// We should have thrown in the middle of cleaning up "two", which means that
// there should be 20 calls to the destructor and the try block should exit
// before the assertion.
if ( gConstructorCounter != 20 || gDestructorCounter != 20 ) {
std::printf("Unexpected Constructor/Destructor calls (1D)\n");
std::printf("Expected (20, 20), but got (%d, %d)\n", gConstructorCounter, gDestructorCounter);
retVal = 1;
}
// Try throwing from a destructor - should be fine.
gConstructorCounter = gDestructorCounter = 0;
gConstructorThrowTarget = -1;
gDestructorThrowTarget = 5;
try { vec_on_stack v; }
catch ( int i ) {}
if ( gConstructorCounter != gDestructorCounter ) {
std::printf("Mismatched Constructor/Destructor calls (2D)\n");
std::printf("%d constructors, but %d destructors\n", gConstructorCounter, gDestructorCounter);
retVal = 1;
}
return retVal;
}
#endif
int main(int, char**) {
int retVal = 0;
retVal += test_empty ();
retVal += test_counted ();
#ifndef TEST_HAS_NO_EXCEPTIONS
retVal += test_exception_in_constructor ();
retVal += test_exception_in_destructor ();
#endif
return retVal;
}

View file

@ -0,0 +1,86 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/cstdlib"
#include "third_party/libcxx/exception"
void my_terminate () { exit ( 0 ); }
// Wrapper routines
void *my_alloc2 ( size_t sz ) {
void *p = std::malloc ( sz );
// std::printf ( "Allocated %ld bytes at %lx\n", sz, (unsigned long) p );
return p;
}
void my_dealloc2 ( void *p ) {
// std::printf ( "Freeing %lx\n", (unsigned long) p );
std::free ( p );
}
void my_dealloc3 ( void *p, size_t ) {
// std::printf ( "Freeing %lx (size %ld)\n", (unsigned long) p, sz );
std::free ( p );
}
void my_construct ( void *) {
// std::printf ( "Constructing %lx\n", (unsigned long) p );
}
void my_destruct ( void *) {
// std::printf ( "Destructing %lx\n", (unsigned long) p );
}
int gCounter;
void count_construct ( void * ) { ++gCounter; }
void count_destruct ( void * ) { --gCounter; }
int gConstructorCounter;
int gConstructorThrowTarget;
int gDestructorCounter;
int gDestructorThrowTarget;
void throw_construct ( void * ) { if ( gConstructorCounter == gConstructorThrowTarget ) throw 1; ++gConstructorCounter; }
void throw_destruct ( void * ) { if ( ++gDestructorCounter == gDestructorThrowTarget ) throw 2; }
struct vec_on_stack {
void *storage;
vec_on_stack () : storage ( __cxxabiv1::__cxa_vec_new ( 10, 40, 8, throw_construct, throw_destruct )) {}
~vec_on_stack () { __cxxabiv1::__cxa_vec_delete ( storage, 40, 8, throw_destruct ); }
};
// Make sure the constructors and destructors are matched
void test_exception_in_destructor ( ) {
// Try throwing from a destructor while unwinding the stack -- should abort
gConstructorCounter = gDestructorCounter = 0;
gConstructorThrowTarget = -1;
gDestructorThrowTarget = 5;
try {
vec_on_stack v;
throw 3;
} catch ( int i ) {
}
assert(false && "should never get here");
}
int main () {
std::set_terminate ( my_terminate );
test_exception_in_destructor ();
return 1; // we failed if we get here
}

View file

@ -0,0 +1,66 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
#include "third_party/libcxxabi/include/cxxabi.h"
#include "libc/isystem/stdio.h"
#include "libc/isystem/stdlib.h"
#include "libc/isystem/assert.h"
#include "third_party/libcxx/exception"
#include "third_party/libcxx/memory"
// Disable warning about throw always calling terminate.
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic ignored "-Wterminate"
#endif
// use dtors instead of try/catch
namespace test1 {
struct B {
~B() {
printf("should not be run\n");
exit(10);
}
};
struct A {
~A()
#if __has_feature(cxx_noexcept)
noexcept(false)
#endif
{
B b;
throw 0;
}
};
} // test1
void my_terminate() { exit(0); }
template <class T>
void destroy(void* v)
{
T* t = static_cast<T*>(v);
t->~T();
}
int main(int, char**)
{
std::set_terminate(my_terminate);
{
typedef test1::A Array[10];
Array a[10]; // calls _cxa_vec_dtor
__cxxabiv1::__cxa_vec_dtor(a, 10, sizeof(test1::A), destroy<test1::A>);
assert(false);
}
return 0;
}

View file

@ -0,0 +1,67 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03
// UNSUPPORTED: no-threads
// XFAIL: LIBCXX-FREEBSD-FIXME
// TODO: This test does start working with newer updates of the mingw-w64
// toolchain, when it includes the following commit:
// https://github.com/mingw-w64/mingw-w64/commit/71eddccd746c56d9cde28bb5620d027d49259de9
// Thus, remove this UNSUPPORTED marking after the next update of the CI
// toolchain.
// UNSUPPORTED: target={{.*-windows-gnu}}
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/thread"
#include "third_party/libcxxabi/libcxx/test/support/make_test_thread.hh"
int seq = 0;
class OrderChecker {
public:
explicit OrderChecker(int n) : n_{n} { }
~OrderChecker() {
assert(seq++ == n_);
}
private:
int n_;
};
template <int ID>
class CreatesThreadLocalInDestructor {
public:
~CreatesThreadLocalInDestructor() {
thread_local OrderChecker checker{ID};
}
};
OrderChecker global{7};
void thread_fn() {
static OrderChecker fn_static{5};
thread_local CreatesThreadLocalInDestructor<2> creates_tl2;
thread_local OrderChecker fn_thread_local{1};
thread_local CreatesThreadLocalInDestructor<0> creates_tl0;
}
int main(int, char**) {
static OrderChecker fn_static{6};
support::make_test_thread(thread_fn).join();
assert(seq == 3);
thread_local OrderChecker fn_thread_local{4};
thread_local CreatesThreadLocalInDestructor<3> creates_tl;
return 0;
}

View file

@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// This tests that libc++abi still provides __cxa_uncaught_exception() for
// ABI compatibility, even though the Standard doesn't require it to.
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/cassert"
// namespace __cxxabiv1 {
// extern bool __cxa_uncaught_exception () throw();
// }
struct A {
~A() { assert( __cxxabiv1::__cxa_uncaught_exception()); }
};
int main () {
try { A a; throw 3; assert(false); }
catch (int) {}
}

View file

@ -0,0 +1,30 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// __cxa_uncaught_exceptions is not re-exported from libc++ until macOS 10.15.
// XFAIL: stdlib=apple-libc++ && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14}}
#include "third_party/libcxxabi/include/cxxabi.h"
#include "third_party/libcxx/cassert"
// namespace __cxxabiv1 {
// extern unsigned int __cxa_uncaught_exceptions() throw();
// }
struct A {
A(unsigned cnt) : data_(cnt) {}
~A() { assert( data_ == __cxxabiv1::__cxa_uncaught_exceptions()); }
unsigned data_;
};
int main () {
try { A a(1); throw 3; assert(false); }
catch (int) {}
}

View file

@ -0,0 +1,89 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03
// ADDITIONAL_COMPILE_FLAGS: -Wno-unused-function
#include "third_party/libcxx/cassert"
#include "third_party/libcxx/utility"
#include "third_party/libcxxabi/demangle/ItaniumDemangle.h"
void testPODSmallVector() {
{ // {push/pop}_back
itanium_demangle::PODSmallVector<int, 1> PSV;
PSV.push_back(0);
PSV.push_back(1);
PSV.push_back(2);
PSV.push_back(3);
for (int i = 0; i < 4; ++i)
assert(PSV[i] == i);
PSV.pop_back();
for (int i = 0; i < 3; ++i)
assert(PSV[i] == i);
PSV.pop_back();
PSV.pop_back();
assert(!PSV.empty() && PSV.size() == 1);
PSV.pop_back();
assert(PSV.empty() && PSV.size() == 0);
}
{
itanium_demangle::PODSmallVector<int, 1> PSV1;
PSV1.push_back(1);
PSV1.push_back(2);
PSV1.push_back(3);
itanium_demangle::PODSmallVector<int, 1> PSV2;
std::swap(PSV1, PSV2);
assert(PSV1.size() == 0);
assert(PSV2.size() == 3);
int i = 1;
for (int x : PSV2) {
assert(x == i);
++i;
}
assert(i == 4);
std::swap(PSV1, PSV2);
assert(PSV1.size() == 3);
assert(PSV2.size() == 0);
i = 1;
for (int x : PSV1) {
assert(x == i);
++i;
}
assert(i == 4);
}
{
itanium_demangle::PODSmallVector<int, 10> PSV1;
itanium_demangle::PODSmallVector<int, 10> PSV2;
PSV1.push_back(0);
PSV1.push_back(1);
PSV1.push_back(2);
assert(PSV1.size() == 3);
assert(PSV2.size() == 0);
std::swap(PSV1, PSV2);
assert(PSV1.size() == 0);
assert(PSV2.size() == 3);
int i = 0;
for (int x : PSV2) {
assert(x == i);
++i;
}
for (int x : PSV1) {
assert(false);
(void)x;
}
}
}
int main(int, char**) {
testPODSmallVector();
return 0;
}

View file

@ -0,0 +1,103 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
#include "libc/isystem/assert.h"
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wunreachable-code"
#endif
struct A
{
static int count;
int id_;
A() : id_(++count) {}
~A() {assert(id_ == count--);}
private:
A(const A&);
A& operator=(const A&);
};
int A::count = 0;
struct B
{
static int count;
int id_;
B() : id_(++count) {}
~B() {assert(id_ == count--);}
private:
B(const B&);
B& operator=(const B&);
};
int B::count = 0;
struct C
{
static int count;
int id_;
C() : id_(++count) {}
~C() {assert(id_ == count--);}
private:
C(const C&);
C& operator=(const C&);
};
int C::count = 0;
void f2()
{
C c;
A a;
throw 55;
B b;
}
void f1()
{
A a;
B b;
f2();
C c;
}
int main(int, char**)
{
try
{
f1();
assert(false);
}
catch (int* i)
{
assert(false);
}
catch (long i)
{
assert(false);
}
catch (int i)
{
assert(i == 55);
}
catch (...)
{
assert(false);
}
assert(A::count == 0);
assert(B::count == 0);
assert(C::count == 0);
return 0;
}

View file

@ -0,0 +1,105 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// REQUIRES: c++03 || c++11 || c++14
#include "libc/isystem/assert.h"
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wunreachable-code"
#pragma GCC diagnostic ignored "-Wdeprecated" // dynamic exception specifications are deprecated
#endif
struct A
{
static int count;
int id_;
A() : id_(++count) {}
~A() {assert(id_ == count--);}
private:
A(const A&);
A& operator=(const A&);
};
int A::count = 0;
struct B
{
static int count;
int id_;
B() : id_(++count) {}
~B() {assert(id_ == count--);}
private:
B(const B&);
B& operator=(const B&);
};
int B::count = 0;
struct C
{
static int count;
int id_;
C() : id_(++count) {}
~C() {assert(id_ == count--);}
private:
C(const C&);
C& operator=(const C&);
};
int C::count = 0;
void f2()
{
C c;
A a;
throw 55;
B b;
}
void f1() throw (long, char, int, double)
{
A a;
B b;
f2();
C c;
}
int main(int, char**)
{
try
{
f1();
assert(false);
}
catch (int* i)
{
assert(false);
}
catch (long i)
{
assert(false);
}
catch (int i)
{
assert(i == 55);
}
catch (...)
{
assert(false);
}
assert(A::count == 0);
assert(B::count == 0);
assert(C::count == 0);
return 0;
}

View file

@ -0,0 +1,111 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// REQUIRES: c++03 || c++11 || c++14
#include "third_party/libcxx/exception"
#include "libc/isystem/stdlib.h"
#include "libc/isystem/assert.h"
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wunreachable-code"
#pragma GCC diagnostic ignored "-Wdeprecated" // dynamic exception specifications are deprecated
#endif
struct A
{
static int count;
int id_;
A() : id_(++count) {}
~A() {assert(id_ == count--);}
private:
A(const A&);
A& operator=(const A&);
};
int A::count = 0;
struct B
{
static int count;
int id_;
B() : id_(++count) {}
~B() {assert(id_ == count--);}
private:
B(const B&);
B& operator=(const B&);
};
int B::count = 0;
struct C
{
static int count;
int id_;
C() : id_(++count) {}
~C() {assert(id_ == count--);}
private:
C(const C&);
C& operator=(const C&);
};
int C::count = 0;
void f2()
{
C c;
A a;
throw 55;
B b;
}
void f1() throw (long, char, double)
{
A a;
B b;
f2();
C c;
}
void u_handler()
{
exit(0);
}
int main(int, char**)
{
std::set_unexpected(u_handler);
try
{
f1();
assert(false);
}
catch (int* i)
{
assert(false);
}
catch (long i)
{
assert(false);
}
catch (int i)
{
assert(i == 55);
}
catch (...)
{
assert(false);
}
assert(false);
return 0;
}

View file

@ -0,0 +1,117 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// REQUIRES: c++03 || c++11 || c++14
#include "third_party/libcxx/exception"
#include "libc/isystem/stdlib.h"
#include "libc/isystem/assert.h"
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wunreachable-code"
#pragma GCC diagnostic ignored "-Wdeprecated" // dynamic exception specifications are deprecated
#endif
struct A
{
static int count;
int id_;
A() : id_(++count) {}
~A() {assert(id_ == count--);}
private:
A(const A&);
A& operator=(const A&);
};
int A::count = 0;
struct B
{
static int count;
int id_;
B() : id_(++count) {}
~B() {assert(id_ == count--);}
private:
B(const B&);
B& operator=(const B&);
};
int B::count = 0;
struct C
{
static int count;
int id_;
C() : id_(++count) {}
~C() {assert(id_ == count--);}
private:
C(const C&);
C& operator=(const C&);
};
int C::count = 0;
void f2()
{
C c;
A a;
throw 55;
B b;
}
void f1() throw (long, char, double)
{
A a;
B b;
f2();
C c;
}
void u_handler()
{
throw 'a';
}
int main(int, char**)
{
std::set_unexpected(u_handler);
try
{
f1();
assert(false);
}
catch (int* i)
{
assert(false);
}
catch (long i)
{
assert(false);
}
catch (int i)
{
assert(false);
}
catch (char c)
{
assert(c == 'a');
}
catch (...)
{
assert(false);
}
assert(A::count == 0);
assert(B::count == 0);
assert(C::count == 0);
return 0;
}

View file

@ -0,0 +1,121 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
// REQUIRES: c++03 || c++11 || c++14
#include "third_party/libcxx/exception"
#include "libc/isystem/stdlib.h"
#include "libc/isystem/assert.h"
#if defined(__GNUC__)
#pragma GCC diagnostic ignored "-Wunreachable-code"
#pragma GCC diagnostic ignored "-Wdeprecated" // dynamic exception specifications are deprecated
#endif
struct A
{
static int count;
int id_;
A() : id_(++count) {}
~A() {assert(id_ == count--);}
private:
A(const A&);
A& operator=(const A&);
};
int A::count = 0;
struct B
{
static int count;
int id_;
B() : id_(++count) {}
~B() {assert(id_ == count--);}
private:
B(const B&);
B& operator=(const B&);
};
int B::count = 0;
struct C
{
static int count;
int id_;
C() : id_(++count) {}
~C() {assert(id_ == count--);}
private:
C(const C&);
C& operator=(const C&);
};
int C::count = 0;
void f2()
{
C c;
A a;
throw 55;
B b;
}
void f1() throw (long, char, double, std::bad_exception)
{
A a;
B b;
f2();
C c;
}
void u_handler()
{
throw;
}
int main(int, char**)
{
std::set_unexpected(u_handler);
try
{
f1();
assert(false);
}
catch (int* i)
{
assert(false);
}
catch (long i)
{
assert(false);
}
catch (int i)
{
assert(false);
}
catch (char c)
{
assert(false);
}
catch (const std::bad_exception& e)
{
assert(true);
}
catch (...)
{
assert(false);
}
assert(A::count == 0);
assert(B::count == 0);
assert(C::count == 0);
return 0;
}

View file

@ -0,0 +1,263 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: no-exceptions
#include "third_party/libcxx/exception"
#include "libc/isystem/stdlib.h"
#include "libc/isystem/assert.h"
#include "libc/stdio/stdio.h"
// Suppress diagnostics about deprecated volatile operations
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic ignored "-Wvolatile"
#endif
// Compile with -Os to get compiler uses float registers to hold float variables
double get_(int x) { return (double)x; }
double (* volatile get)(int) = get_;
volatile int counter;
double try1(bool v) {
double a = get(0);
double b = get(1);
for (counter = 100; counter; counter = counter - 1)
a += get(1) + b;
if (v) throw 10;
return get(0)+a+b;
}
double try2(bool v) {
double a = get(0);
double b = get(1);
double c = get(2);
for (counter = 100; counter; counter = counter - 1)
a += get(1) + b + c;
if (v) throw 10;
return get(0)+a+b+c;
}
double try3(bool v) {
double a = get(0);
double b = get(1);
double c = get(2);
double d = get(3);
for (counter = 100; counter; counter = counter - 1)
a += get(1) + b + c + d;
if (v) throw 10;
return get(0)+a+b+c+d;
}
double try4(bool v) {
double a = get(0);
double b = get(0);
double c = get(0);
double d = get(0);
double e = get(0);
for (counter = 100; counter; counter = counter - 1)
a += get(1) + b+c+d+e;
if (v) throw 10;
return get(0)+a+b+c+d+e;
}
double try5(bool v) {
double a = get(0);
double b = get(0);
double c = get(0);
double d = get(0);
double e = get(0);
double f = get(0);
for (counter = 100; counter; counter = counter - 1)
a += get(1) + b+c+d+e+f;
if (v) throw 10;
return get(0)+a+b+c+d+e+f;
}
double try6(bool v) {
double a = get(0);
double b = get(0);
double c = get(0);
double d = get(0);
double e = get(0);
double f = get(0);
double g = get(0);
for (counter = 100; counter; counter = counter - 1)
a += get(1) + b+c+d+e+f+g;
if (v) throw 10;
return get(0)+a+b+c+d+e+f+g;
}
double try7(bool v) {
double a = get(0);
double b = get(0);
double c = get(0);
double d = get(0);
double e = get(0);
double f = get(0);
double g = get(0);
double h = get(0);
for (counter = 100; counter; counter = counter - 1)
a += get(1) + b+c+d+e+f+g+h;
if (v) throw 10;
return get(0)+a+b+c+d+e+f+g+h;
}
double try8(bool v) {
double a = get(0);
double b = get(0);
double c = get(0);
double d = get(0);
double e = get(0);
double f = get(0);
double g = get(0);
double h = get(0);
double i = get(0);
for (counter = 100; counter; counter = counter - 1)
a += get(1) + b+c+d+e+f+g+h+i;
if (v) throw 10;
return get(0)+a+b+c+d+e+f+g+h+i;
}
double foo()
{
double a = get(1);
double b = get(2);
double c = get(3);
double d = get(4);
double e = get(5);
double f = get(6);
double g = get(7);
double h = get(8);
try {
try1(true);
}
catch (int) {
}
assert(a == get(1));
assert(b == get(2));
assert(c == get(3));
assert(d == get(4));
assert(e == get(5));
assert(f == get(6));
assert(g == get(7));
assert(h == get(8));
try {
try2(true);
}
catch (int) {
}
assert(a == get(1));
assert(b == get(2));
assert(c == get(3));
assert(d == get(4));
assert(e == get(5));
assert(f == get(6));
assert(g == get(7));
assert(h == get(8));
try {
try3(true);
}
catch (int) {
}
assert(a == get(1));
assert(b == get(2));
assert(c == get(3));
assert(d == get(4));
assert(e == get(5));
assert(f == get(6));
assert(g == get(7));
assert(h == get(8));
try {
try4(true);
}
catch (int) {
}
assert(a == get(1));
assert(b == get(2));
assert(c == get(3));
assert(d == get(4));
assert(e == get(5));
assert(f == get(6));
assert(g == get(7));
assert(h == get(8));
try {
try5(true);
}
catch (int) {
}
assert(a == get(1));
assert(b == get(2));
assert(c == get(3));
assert(d == get(4));
assert(e == get(5));
assert(f == get(6));
assert(g == get(7));
assert(h == get(8));
try {
try6(true);
}
catch (int) {
}
assert(a == get(1));
assert(b == get(2));
assert(c == get(3));
assert(d == get(4));
assert(e == get(5));
assert(f == get(6));
assert(g == get(7));
assert(h == get(8));
try {
try7(true);
}
catch (int) {
}
assert(a == get(1));
assert(b == get(2));
assert(c == get(3));
assert(d == get(4));
assert(e == get(5));
assert(f == get(6));
assert(g == get(7));
assert(h == get(8));
try {
try8(true);
}
catch (int) {
}
assert(a == get(1));
assert(b == get(2));
assert(c == get(3));
assert(d == get(4));
assert(e == get(5));
assert(f == get(6));
assert(g == get(7));
assert(h == get(8));
return a+b+c+d+e+f+g+h;
}
int main(int, char**) {
foo();
return 0;
}