diff --git a/stl/inc/functional b/stl/inc/functional index 4d7e5290cde..f40b516e819 100644 --- a/stl/inc/functional +++ b/stl/inc/functional @@ -795,7 +795,8 @@ private: constexpr size_t _Space_size = (_Small_object_num_ptrs - 1) * sizeof(void*); template // determine whether _Impl must be dynamically allocated -_INLINE_VAR constexpr bool _Is_large = (_Space_size < sizeof(_Impl)) || !_Impl::_Nothrow_move::value; +_INLINE_VAR constexpr bool _Is_large = sizeof(_Impl) > _Space_size || alignof(_Impl) > alignof(max_align_t) + || !_Impl::_Nothrow_move::value; #if _HAS_FUNCTION_ALLOCATOR_SUPPORT // CLASS TEMPLATE _Func_impl diff --git a/tests/std/test.lst b/tests/std/test.lst index aca5c46b5d3..fa0e5e35ce7 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -157,6 +157,7 @@ tests\Dev11_1158803_regex_thread_safety tests\Dev11_1180290_filesystem_error_code tests\GH_000457_system_error_message tests\GH_000545_include_compare +tests\GH_000690_overaligned_function tests\P0024R2_parallel_algorithms_adjacent_difference tests\P0024R2_parallel_algorithms_adjacent_find tests\P0024R2_parallel_algorithms_all_of diff --git a/tests/std/tests/GH_000690_overaligned_function/env.lst b/tests/std/tests/GH_000690_overaligned_function/env.lst new file mode 100644 index 00000000000..19f025bd0e6 --- /dev/null +++ b/tests/std/tests/GH_000690_overaligned_function/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\usual_matrix.lst diff --git a/tests/std/tests/GH_000690_overaligned_function/test.cpp b/tests/std/tests/GH_000690_overaligned_function/test.cpp new file mode 100644 index 00000000000..effd03765af --- /dev/null +++ b/tests/std/tests/GH_000690_overaligned_function/test.cpp @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#pragma warning(disable : 4324) // structure was padded due to alignment specifier + +// SFO (Small Functor Optimization) should not happen +struct alignas(2 * alignof(std::max_align_t)) overaligned_t { + char non_empty; + + void operator()(const void* const storage, const std::size_t storage_size) const { + const auto storage_ptr_value = reinterpret_cast(storage); + const auto this_ptr_value = reinterpret_cast(this); + + // Platform-specific behavior not covered by Standard C++, but fine for this test + assert(this_ptr_value < storage_ptr_value || this_ptr_value >= storage_ptr_value + storage_size); + + // Before C++17, alignas isn't helpful for aligning allocations via "new" +#ifdef __cpp_aligned_new + assert(this_ptr_value % alignof(overaligned_t) == 0); +#endif + } +}; + +// SFO should happen +struct not_overaligned_t { + char data[sizeof(overaligned_t)]; + + void operator()(const void* const storage, const std::size_t storage_size) const { + const auto storage_ptr_value = reinterpret_cast(storage); + const auto this_ptr_value = reinterpret_cast(this); + + // Platform-specific behavior not covered by Standard C++, but fine for this test + assert(this_ptr_value >= storage_ptr_value && this_ptr_value < storage_ptr_value + storage_size); + } +}; + +static_assert(alignof(overaligned_t) > alignof(std::max_align_t), "overaligned_t is not overaligned"); + +using function_t = std::function; + +struct functions_t { + function_t first{overaligned_t{}}; + char smallest_pad; + function_t second{overaligned_t{}}; + function_t third{overaligned_t{}}; +}; + +int main() { + functions_t functions; + functions.first(&functions.first, sizeof(functions.first)); + functions.second(&functions.second, sizeof(functions.second)); + functions.third(&functions.third, sizeof(functions.third)); + + function_t sfo{not_overaligned_t{}}; + sfo(&sfo, sizeof(sfo)); + + return 0; +}