[libc++] Support Microsoft ABI without vcruntime headers

The vcruntime headers are hairy and clash with both libc++ headers
themselves and other libraries. libc++ normally deals with the clashes
by deferring to the vcruntime headers and silencing its own definitions,
but for clients which don't want to depend on vcruntime headers, it's
desirable to support the opposite, i.e. have libc++ provide its own
definitions.

Certain operator new/delete replacement scenarios are not currently
supported in this mode, which requires some tests to be marked XFAIL.
The added documentation has more details.

Differential Revision: https://reviews.llvm.org/D38522

llvm-svn: 315234
This commit is contained in:
Shoaib Meenai 2017-10-09 19:25:17 +00:00
parent 6ab4d075ff
commit 492d7134f3
12 changed files with 137 additions and 27 deletions

View File

@ -615,6 +615,7 @@ config_define_if(LIBCXX_HAS_PTHREAD_API _LIBCPP_HAS_THREAD_API_PTHREAD)
config_define_if(LIBCXX_HAS_EXTERNAL_THREAD_API _LIBCPP_HAS_THREAD_API_EXTERNAL)
config_define_if(LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY _LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL)
config_define_if(LIBCXX_HAS_MUSL_LIBC _LIBCPP_HAS_MUSL_LIBC)
config_define_if(LIBCXX_NO_VCRUNTIME _LIBCPP_NO_VCRUNTIME)
if (LIBCXX_ABI_DEFINES)
set(abi_defines)

View File

@ -185,6 +185,26 @@ thread safety annotations.
* Giving `set`, `map`, `multiset`, `multimap` a comparator which is not
const callable.
**_LIBCPP_NO_VCRUNTIME**:
Microsoft's C and C++ headers are fairly entangled, and some of their C++
headers are fairly hard to avoid. In particular, `vcruntime_new.h` gets pulled
in from a lot of other headers and provides definitions which clash with
libc++ headers, such as `nothrow_t` (note that `nothrow_t` is a struct, so
there's no way for libc++ to provide a compatible definition, since you can't
have multiple definitions).
By default, libc++ solves this problem by deferring to Microsoft's vcruntime
headers where needed. However, it may be undesirable to depend on vcruntime
headers, since they may not always be available in cross-compilation setups,
or they may clash with other headers. The `_LIBCPP_NO_VCRUNTIME` macro
prevents libc++ from depending on vcruntime headers. Consequently, it also
prevents libc++ headers from being interoperable with vcruntime headers (from
the aforementioned clashes), so users of this macro are promising to not
attempt to combine libc++ headers with the problematic vcruntime headers. This
macro also currently prevents certain `operator new`/`operator delete`
replacement scenarios from working, e.g. replacing `operator new` and
expecting a non-replaced `operator new[]` to call the replaced `operator new`.
C++17 Specific Configuration Macros
-----------------------------------
**_LIBCPP_ENABLE_CXX17_REMOVED_FEATURES**:

View File

@ -25,6 +25,7 @@
#cmakedefine _LIBCPP_HAS_THREAD_API_EXTERNAL
#cmakedefine _LIBCPP_HAS_THREAD_LIBRARY_EXTERNAL
#cmakedefine _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS
#cmakedefine _LIBCPP_NO_VCRUNTIME
@_LIBCPP_ABI_DEFINES@

View File

@ -82,7 +82,7 @@ template <class E> void rethrow_if_nested(const E& e);
#include <cstdlib>
#include <type_traits>
#if defined(_LIBCPP_ABI_MICROSOFT)
#if defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_NO_VCRUNTIME)
#include <vcruntime_exception.h>
#endif
@ -93,7 +93,7 @@ template <class E> void rethrow_if_nested(const E& e);
namespace std // purposefully not using versioning namespace
{
#if !defined(_LIBCPP_ABI_MICROSOFT)
#if !defined(_LIBCPP_ABI_MICROSOFT) || defined(_LIBCPP_NO_VCRUNTIME)
class _LIBCPP_EXCEPTION_ABI exception
{
public:
@ -110,7 +110,7 @@ public:
virtual ~bad_exception() _NOEXCEPT;
virtual const char* what() const _NOEXCEPT;
};
#endif // !_LIBCPP_ABI_MICROSOFT
#endif // !_LIBCPP_ABI_MICROSOFT || _LIBCPP_NO_VCRUNTIME
#if _LIBCPP_STD_VER <= 14 \
|| defined(_LIBCPP_ENABLE_CXX17_REMOVED_UNEXPECTED_FUNCTIONS) \

View File

@ -92,7 +92,7 @@ void operator delete[](void* ptr, void*) noexcept;
#include <cstdlib>
#endif
#if defined(_LIBCPP_ABI_MICROSOFT)
#if defined(_LIBCPP_ABI_MICROSOFT) && !defined(_LIBCPP_NO_VCRUNTIME)
#include <new.h>
#endif
@ -114,7 +114,7 @@ void operator delete[](void* ptr, void*) noexcept;
namespace std // purposefully not using versioning namespace
{
#if !defined(_LIBCPP_ABI_MICROSOFT)
#if !defined(_LIBCPP_ABI_MICROSOFT) || defined(_LIBCPP_NO_VCRUNTIME)
struct _LIBCPP_TYPE_VIS nothrow_t {};
extern _LIBCPP_FUNC_VIS const nothrow_t nothrow;
@ -140,7 +140,7 @@ typedef void (*new_handler)();
_LIBCPP_FUNC_VIS new_handler set_new_handler(new_handler) _NOEXCEPT;
_LIBCPP_FUNC_VIS new_handler get_new_handler() _NOEXCEPT;
#endif // !_LIBCPP_ABI_MICROSOFT
#endif // !_LIBCPP_ABI_MICROSOFT || _LIBCPP_NO_VCRUNTIME
_LIBCPP_NORETURN _LIBCPP_FUNC_VIS void __throw_bad_alloc(); // not in C++ spec
@ -174,7 +174,7 @@ enum align_val_t { __zero = 0, __max = (size_t)-1 };
#define _THROW_BAD_ALLOC
#endif
#if !defined(_LIBCPP_ABI_MICROSOFT)
#if !defined(_LIBCPP_ABI_MICROSOFT) || defined(_LIBCPP_NO_VCRUNTIME)
_LIBCPP_OVERRIDABLE_FUNC_VIS void* operator new(std::size_t __sz) _THROW_BAD_ALLOC;
_LIBCPP_OVERRIDABLE_FUNC_VIS void* operator new(std::size_t __sz, const std::nothrow_t&) _NOEXCEPT _NOALIAS;
@ -215,7 +215,7 @@ inline _LIBCPP_INLINE_VISIBILITY void* operator new[](std::size_t, void* __p) _N
inline _LIBCPP_INLINE_VISIBILITY void operator delete (void*, void*) _NOEXCEPT {}
inline _LIBCPP_INLINE_VISIBILITY void operator delete[](void*, void*) _NOEXCEPT {}
#endif // !_LIBCPP_ABI_MICROSOFT
#endif // !_LIBCPP_ABI_MICROSOFT || _LIBCPP_NO_VCRUNTIME
_LIBCPP_BEGIN_NAMESPACE_STD

View File

@ -15,7 +15,9 @@
#include "include/atomic_support.h"
#if defined(_LIBCPP_ABI_MICROSOFT)
// nothing todo
#if defined(_LIBCPP_NO_VCRUNTIME)
#include "support/runtime/new_handler_fallback.ipp"
#endif
#elif defined(LIBCXX_BUILDING_LIBCXXABI)
#include <cxxabi.h>
#elif defined(LIBCXXRT)
@ -54,7 +56,8 @@ __throw_bad_alloc()
} // std
#if !defined(__GLIBCXX__) && !defined(_LIBCPP_ABI_MICROSOFT) && \
#if !defined(__GLIBCXX__) && \
(!defined(_LIBCPP_ABI_MICROSOFT) || defined(_LIBCPP_NO_VCRUNTIME)) && \
!defined(_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS)
// Implement all new and delete operators as weak definitions
@ -300,4 +303,4 @@ operator delete[] (void* ptr, size_t, std::align_val_t alignment) _NOEXCEPT
}
#endif // !_LIBCPP_HAS_NO_ALIGNED_ALLOCATION
#endif // !__GLIBCXX__ && !_LIBCPP_ABI_MICROSOFT && !_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS
#endif // !__GLIBCXX__ && (!_LIBCPP_ABI_MICROSOFT || _LIBCPP_NO_VCRUNTIME) && !_LIBCPP_DISABLE_NEW_DELETE_DEFINITIONS

View File

@ -14,12 +14,35 @@
#include <stdio.h>
#include <stdlib.h>
#include <eh.h>
#include <corecrt_terminate.h>
#if !defined(_ACRTIMP)
#define _ACRTIMP __declspec(dllimport)
#endif
#if !defined(_VCRTIMP)
#define _VCRTIMP __declspec(dllimport)
#endif
#if !defined(__CRTDECL)
#define __CRTDECL __cdecl
#endif
extern "C" {
typedef void (__CRTDECL* terminate_handler)();
_ACRTIMP terminate_handler __cdecl set_terminate(
terminate_handler _NewTerminateHandler) throw();
_ACRTIMP terminate_handler __cdecl _get_terminate();
typedef void (__CRTDECL* unexpected_handler)();
_VCRTIMP unexpected_handler __cdecl set_unexpected(
unexpected_handler _NewUnexpectedHandler) throw();
_VCRTIMP unexpected_handler __cdecl _get_unexpected();
_VCRTIMP int __cdecl __uncaught_exceptions();
}
namespace std {
// libcxxrt provides implementations of these functions itself.
unexpected_handler
set_unexpected(unexpected_handler func) _NOEXCEPT {
return ::set_unexpected(func);
@ -114,4 +137,54 @@ bad_typeid::what() const _NOEXCEPT
return "std::bad_typeid";
}
#if defined(_LIBCPP_NO_VCRUNTIME)
exception::~exception() _NOEXCEPT
{
}
const char* exception::what() const _NOEXCEPT
{
return "std::exception";
}
bad_exception::~bad_exception() _NOEXCEPT
{
}
const char* bad_exception::what() const _NOEXCEPT
{
return "std::bad_exception";
}
bad_alloc::bad_alloc() _NOEXCEPT
{
}
bad_alloc::~bad_alloc() _NOEXCEPT
{
}
const char*
bad_alloc::what() const _NOEXCEPT
{
return "std::bad_alloc";
}
bad_array_new_length::bad_array_new_length() _NOEXCEPT
{
}
bad_array_new_length::~bad_array_new_length() _NOEXCEPT
{
}
const char*
bad_array_new_length::what() const _NOEXCEPT
{
return "bad_array_new_length";
}
#endif // _LIBCPP_NO_VCRUNTIME
} // namespace std

View File

@ -10,26 +10,32 @@
#include <stdio.h>
#include <stdlib.h>
#include <yvals.h> // for _CRTIMP2_PURE
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCreate(_Out_ void*);
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrDestroy(_Inout_ void*);
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCopy(_Out_ void*,
_In_ const void*);
#if !defined(_CRTIMP2_PURE)
#define _CRTIMP2_PURE __declspec(dllimport)
#endif
#if !defined(__CLRCALL_PURE_OR_CDECL)
#define __CLRCALL_PURE_OR_CDECL __cdecl
#endif
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCreate(void*);
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrDestroy(void*);
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrCopy(void*,
const void*);
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL
__ExceptionPtrAssign(_Inout_ void*, _In_ const void*);
__ExceptionPtrAssign(void*, const void*);
_CRTIMP2_PURE bool __CLRCALL_PURE_OR_CDECL
__ExceptionPtrCompare(_In_ const void*, _In_ const void*);
__ExceptionPtrCompare(const void*, const void*);
_CRTIMP2_PURE bool __CLRCALL_PURE_OR_CDECL
__ExceptionPtrToBool(_In_ const void*);
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrSwap(_Inout_ void*,
_Inout_ void*);
__ExceptionPtrToBool(const void*);
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL __ExceptionPtrSwap(void*, void*);
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL
__ExceptionPtrCurrentException(_Out_ void*);
__ExceptionPtrCurrentException(void*);
[[noreturn]] _CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL
__ExceptionPtrRethrow(_In_ const void*);
__ExceptionPtrRethrow(const void*);
_CRTIMP2_PURE void __CLRCALL_PURE_OR_CDECL
__ExceptionPtrCopyException(_Inout_ void*, _In_ const void*, _In_ const void*);
__ExceptionPtrCopyException(void*, const void*, const void*);
namespace std {

View File

@ -10,6 +10,7 @@
// test operator new [] nothrow by replacing only operator new
// UNSUPPORTED: sanitizer-new-delete
// XFAIL: libcpp-no-vcruntime
#include <new>
#include <cstddef>

View File

@ -10,6 +10,7 @@
// test operator new[] replacement by replacing only operator new
// UNSUPPORTED: sanitizer-new-delete
// XFAIL: libcpp-no-vcruntime
#include <new>

View File

@ -10,6 +10,7 @@
// test operator new nothrow by replacing only operator new
// UNSUPPORTED: sanitizer-new-delete
// XFAIL: libcpp-no-vcruntime
#include <new>
#include <cstddef>

View File

@ -668,6 +668,9 @@ class Configuration(object):
self.config.available_features.add('libcpp-abi-version-v%s'
% feature_macros[m])
continue
if m == '_LIBCPP_NO_VCRUNTIME':
self.config.available_features.add('libcpp-no-vcruntime')
continue
assert m.startswith('_LIBCPP_HAS_') or m.startswith('_LIBCPP_ABI_')
m = m.lower()[1:].replace('_', '-')
self.config.available_features.add(m)