Avoid using std::max_align_t in pre-C++11 mode

Always depend on the compiler to have a correct implementation of
max_align_t in stddef.h and don't provide a fallback. For pre-C++11,
require __STDCPP_NEW_ALIGNMENT__ in <new> as provided by clang in all
standard modes. Adjust test cases to avoid testing or using max_align_t
in pre-C++11 mode and also to better deal with alignof(max_align_t)>16.
Document requirements of the alignment tests around natural alignment of
power-of-two-sized types.

Differential revision: https://reviews.llvm.org/D73245
This commit is contained in:
Joerg Sonnenberger 2020-04-04 00:48:02 +02:00
parent a8c8b627f2
commit 98f77828a9
10 changed files with 96 additions and 23 deletions
libcxx
include
test
libcxx
experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem
language.support/support.dynamic
std
containers/sequences/array
depr/depr.c.headers
language.support/support.types
utilities/meta/meta.trans/meta.trans.other

View File

@ -25,7 +25,7 @@ Types:
ptrdiff_t
size_t
max_align_t
max_align_t // C++11
nullptr_t
byte // C++17
@ -49,12 +49,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD
using ::ptrdiff_t;
using ::size_t;
#if defined(__CLANG_MAX_ALIGN_T_DEFINED) || defined(_GCC_MAX_ALIGN_T) || \
defined(__DEFINED_max_align_t) || defined(__NetBSD__)
// Re-use the compiler's <stddef.h> max_align_t where possible.
#if !defined(_LIBCPP_CXX03_LANG)
using ::max_align_t;
#else
typedef long double max_align_t;
#endif
template <class _Tp> struct __libcpp_is_integral { enum { value = 0 }; };

View File

@ -31,7 +31,7 @@ Types:
ptrdiff_t
size_t
max_align_t
max_align_t // C++11
nullptr_t
*/
@ -51,12 +51,6 @@ extern "C++" {
using std::nullptr_t;
}
// Re-use the compiler's <stddef.h> max_align_t where possible.
#if !defined(__CLANG_MAX_ALIGN_T_DEFINED) && !defined(_GCC_MAX_ALIGN_T) && \
!defined(__DEFINED_max_align_t) && !defined(__NetBSD__)
typedef long double max_align_t;
#endif
#endif
#endif // _LIBCPP_STDDEF_H

View File

@ -36,8 +36,13 @@ int main(int, char**)
ex::resource_adaptor<Alloc> r(Alloc{P});
ex::memory_resource & m1 = r;
#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
std::size_t maxSize = std::numeric_limits<std::size_t>::max()
- __STDCPP_DEFAULT_NEW_ALIGNMENT__;
#else
std::size_t maxSize = std::numeric_limits<std::size_t>::max()
- alignof(std::max_align_t);
#endif
m1.deallocate(nullptr, maxSize);
assert(AssertCount == 0);

View File

@ -142,7 +142,11 @@ void operator delete(void* p, size_t n, std::align_val_t a)TEST_NOEXCEPT {
void test_libcpp_dealloc() {
void* p = nullptr;
#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
size_t over_align_val = __STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2;
#else
size_t over_align_val = TEST_ALIGNOF(std::max_align_t) * 2;
#endif
size_t under_align_val = TEST_ALIGNOF(int);
size_t with_size_val = 2;

View File

@ -24,6 +24,14 @@ struct NoDefault {
NoDefault(int) {}
};
#if TEST_STD_VER < 11
struct natural_alignment {
long t1;
long long t2;
double t3;
long double t4;
};
#endif
int main(int, char**)
{
@ -52,13 +60,17 @@ int main(int, char**)
LIBCPP_ASSERT(p != nullptr);
}
{
#if TEST_STD_VER < 11
typedef natural_alignment T;
#else
typedef std::max_align_t T;
#endif
typedef std::array<T, 0> C;
const C c = {};
const T* p = c.data();
LIBCPP_ASSERT(p != nullptr);
std::uintptr_t pint = reinterpret_cast<std::uintptr_t>(p);
assert(pint % TEST_ALIGNOF(std::max_align_t) == 0);
assert(pint % TEST_ALIGNOF(T) == 0);
}
{
typedef NoDefault T;

View File

@ -24,6 +24,15 @@ struct NoDefault {
NoDefault(int) {}
};
#if TEST_STD_VER < 11
struct natural_alignment {
long t1;
long long t2;
double t3;
long double t4;
};
#endif
int main(int, char**)
{
{
@ -50,13 +59,17 @@ int main(int, char**)
LIBCPP_ASSERT(p != nullptr);
}
{
#if TEST_STD_VER < 11
typedef natural_alignment T;
#else
typedef std::max_align_t T;
#endif
typedef std::array<T, 0> C;
const C c = {};
const T* p = c.data();
LIBCPP_ASSERT(p != nullptr);
std::uintptr_t pint = reinterpret_cast<std::uintptr_t>(p);
assert(pint % TEST_ALIGNOF(std::max_align_t) == 0);
assert(pint % TEST_ALIGNOF(T) == 0);
}
#if TEST_STD_VER > 14
{

View File

@ -49,6 +49,15 @@ void test_type() {
test<T, 0>();
}
#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
struct TEST_ALIGNAS(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2) TestType1 {
};
struct TEST_ALIGNAS(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2) TestType2 {
char data[1000];
};
#else
struct TEST_ALIGNAS(TEST_ALIGNOF(std::max_align_t) * 2) TestType1 {
};
@ -56,6 +65,7 @@ struct TEST_ALIGNAS(TEST_ALIGNOF(std::max_align_t) * 2) TestType1 {
struct TEST_ALIGNAS(TEST_ALIGNOF(std::max_align_t) * 2) TestType2 {
char data[1000];
};
#endif
//static_assert(sizeof(void*) == 4, "");
@ -64,7 +74,10 @@ int main(int, char**) {
test_type<int>();
test_type<double>();
test_type<long double>();
#if TEST_STD_VER >= 11
test_type<std::max_align_t>();
#endif
test_type<TestType1>();
test_type<TestType2>();

View File

@ -43,6 +43,7 @@ int main(int, char**)
"decltype(nullptr) == nullptr_t");
static_assert(sizeof(nullptr_t) == sizeof(void*),
"sizeof(nullptr_t) == sizeof(void*)");
#if TEST_STD_VER >= 11
#if TEST_STD_VER > 17
// P0767
static_assert(std::is_trivial<max_align_t>::value,
@ -65,6 +66,7 @@ int main(int, char**)
std::alignment_of<void*>::value,
"std::alignment_of<max_align_t>::value >= "
"std::alignment_of<void*>::value");
#endif
return 0;
}

View File

@ -6,6 +6,8 @@
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++98, c++03
#include <cstddef>
#include <type_traits>
@ -41,5 +43,11 @@ int main(int, char**)
"std::alignment_of<std::max_align_t>::value >= "
"std::alignment_of<void*>::value");
#ifdef __STDCPP_DEFAULT_NEW_ALIGNMENT__
static_assert(std::alignment_of<std::max_align_t>::value <=
__STDCPP_DEFAULT_NEW_ALIGNMENT__,
"max_align_t alignment is no larger than new alignment");
#endif
return 0;
}

View File

@ -17,6 +17,20 @@
#include <cstddef> // for std::max_align_t
#include "test_macros.h"
// The following tests assume naturally aligned types exist
// up to 64bit (double). For larger types, max_align_t should
// give the correct alignment. For pre-C++11 testing, only
// the lower bound is checked.
#if TEST_STD_VER < 11
struct natural_alignment {
long t1;
long long t2;
double t3;
long double t4;
};
#endif
int main(int, char**)
{
{
@ -250,9 +264,6 @@ int main(int, char**)
static_assert(std::alignment_of<T1>::value == 8, "");
static_assert(sizeof(T1) == 16, "");
}
// Use alignof(std::max_align_t) below to find the max alignment instead of
// hardcoding it, because it's different on different platforms.
// (For example 8 on arm and 16 on x86.)
{
typedef std::aligned_storage<16>::type T1;
#if TEST_STD_VER > 11
@ -260,8 +271,15 @@ int main(int, char**)
#endif
static_assert(std::is_trivial<T1>::value, "");
static_assert(std::is_standard_layout<T1>::value, "");
static_assert(std::alignment_of<T1>::value == TEST_ALIGNOF(std::max_align_t),
"");
#if TEST_STD_VER >= 11
const size_t alignment = TEST_ALIGNOF(std::max_align_t) > 16 ?
16 : TEST_ALIGNOF(std::max_align_t);
static_assert(std::alignment_of<T1>::value == alignment, "");
#else
static_assert(std::alignment_of<T1>::value >=
TEST_ALIGNOF(natural_alignment), "");
static_assert(std::alignment_of<T1>::value <= 16, "");
#endif
static_assert(sizeof(T1) == 16, "");
}
{
@ -271,9 +289,17 @@ int main(int, char**)
#endif
static_assert(std::is_trivial<T1>::value, "");
static_assert(std::is_standard_layout<T1>::value, "");
static_assert(std::alignment_of<T1>::value == TEST_ALIGNOF(std::max_align_t),
"");
static_assert(sizeof(T1) == 16 + TEST_ALIGNOF(std::max_align_t), "");
#if TEST_STD_VER >= 11
const size_t alignment = TEST_ALIGNOF(std::max_align_t) > 16 ?
16 : TEST_ALIGNOF(std::max_align_t);
static_assert(std::alignment_of<T1>::value == alignment, "");
static_assert(sizeof(T1) == 16 + alignment, "");
#else
static_assert(std::alignment_of<T1>::value >=
TEST_ALIGNOF(natural_alignment), "");
static_assert(std::alignment_of<T1>::value <= 16);
static_assert(sizeof(T1) % TEST_ALIGNOF(natural_alignment) == 0, "");
#endif
}
{
typedef std::aligned_storage<10>::type T1;