From 9f8fef95047e37ebdbac88dfebecd282e09c47df Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Fri, 15 Sep 2017 00:31:38 +0000 Subject: [PATCH] Fix accidental ADL in std::allocator_traits meta-programming. There were a number of cases where __double_underscore functions, for example __has_construct_test, were called without being qualified, causing ADL to occur. This patch qualifies those calls to avoid this problem. Thanks to David L. Jones for point out the issue initially. llvm-svn: 313324 --- libcxx/include/memory | 12 ++++++------ .../allocator.traits.members/allocate.pass.cpp | 10 ++++++++++ .../allocate_hint.pass.cpp | 18 ++++++++++++++++++ .../construct.pass.cpp | 8 ++++++++ .../deallocate.pass.cpp | 12 ++++++++++++ .../allocator.traits.members/destroy.pass.cpp | 8 ++++++++ .../incomplete_type_helper.h | 14 ++++++++++++++ .../allocator.traits.members/max_size.pass.cpp | 7 +++++++ ...ect_on_container_copy_construction.pass.cpp | 7 +++++++ 9 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/incomplete_type_helper.h diff --git a/libcxx/include/memory b/libcxx/include/memory index 4c1ae46efa3a..351529af0d99 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -1302,7 +1302,7 @@ struct __allocator_traits_rebind<_Alloc<_Tp, _A0, _A1, _A2>, _Up, false> template auto __has_allocate_hint_test(_Alloc&& __a, _SizeType&& __sz, _ConstVoidPtr&& __p) - -> decltype(__a.allocate(__sz, __p), true_type()); + -> decltype((void)__a.allocate(__sz, __p), true_type()); template auto @@ -1313,7 +1313,7 @@ template struct __has_allocate_hint : integral_constant(), + decltype(_VSTD::__has_allocate_hint_test(declval<_Alloc>(), declval<_SizeType>(), declval<_ConstVoidPtr>())), true_type>::value> @@ -1346,7 +1346,7 @@ template struct __has_construct : integral_constant(), + decltype(_VSTD::__has_construct_test(declval<_Alloc>(), declval<_Pointer>(), declval<_Args>()...)), true_type>::value> @@ -1367,7 +1367,7 @@ template struct __has_destroy : integral_constant(), + decltype(_VSTD::__has_destroy_test(declval<_Alloc>(), declval<_Pointer>())), true_type>::value> { @@ -1387,7 +1387,7 @@ template struct __has_max_size : integral_constant())), + decltype(_VSTD::__has_max_size_test(declval<_Alloc&>())), true_type>::value> { }; @@ -1406,7 +1406,7 @@ template struct __has_select_on_container_copy_construction : integral_constant())), + decltype(_VSTD::__has_select_on_container_copy_construction_test(declval<_Alloc&>())), true_type>::value> { }; diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp index ab8179c5ab4d..292d68de9786 100644 --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate.pass.cpp @@ -20,6 +20,8 @@ #include #include +#include "incomplete_type_helper.h" + template struct A { @@ -34,6 +36,14 @@ struct A int main() { + { A a; assert(std::allocator_traits >::allocate(a, 10) == reinterpret_cast(static_cast(0xDEADBEEF))); + } + { + typedef IncompleteHolder* VT; + typedef A Alloc; + Alloc a; + assert(std::allocator_traits::allocate(a, 10) == reinterpret_cast(static_cast(0xDEADBEEF))); + } } diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp index 808284261f7d..90a9154e1840 100644 --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/allocate_hint.pass.cpp @@ -21,6 +21,7 @@ #include #include "test_macros.h" +#include "incomplete_type_helper.h" template struct A @@ -52,12 +53,29 @@ struct B } }; + int main() { #if TEST_STD_VER >= 11 + { A a; assert(std::allocator_traits >::allocate(a, 10, nullptr) == reinterpret_cast(static_cast(0xDEADBEEF))); + } + { + typedef IncompleteHolder* VT; + typedef A Alloc; + Alloc a; + assert(std::allocator_traits::allocate(a, 10, nullptr) == reinterpret_cast(static_cast(0xDEADBEEF))); + } #endif + { B b; assert(std::allocator_traits >::allocate(b, 11, nullptr) == reinterpret_cast(static_cast(0xFEADBEEF))); + } + { + typedef IncompleteHolder* VT; + typedef B Alloc; + Alloc b; + assert(std::allocator_traits::allocate(b, 11, nullptr) == reinterpret_cast(static_cast(0xFEADBEEF))); + } } diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp index 46075f62c6c1..e4aceffdd6b6 100644 --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/construct.pass.cpp @@ -23,6 +23,7 @@ #include #include "test_macros.h" +#include "incomplete_type_helper.h" template struct A @@ -107,6 +108,13 @@ int main() std::allocator_traits >::construct(a, (A2*)&a2, 'd', 5); assert(A2::count == 1); } + { + typedef IncompleteHolder* VT; + typedef A Alloc; + Alloc a; + std::aligned_storage::type store; + std::allocator_traits::construct(a, (VT*)&store, nullptr); + } #if TEST_STD_VER >= 11 { A0::count = 0; diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp index 8176d8b3767a..ecb67adb58e9 100644 --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/deallocate.pass.cpp @@ -20,6 +20,8 @@ #include #include +#include "incomplete_type_helper.h" + int called = 0; template @@ -37,7 +39,17 @@ struct A int main() { + { A a; std::allocator_traits >::deallocate(a, reinterpret_cast(static_cast(0xDEADBEEF)), 10); assert(called == 1); + } + called = 0; + { + typedef IncompleteHolder* VT; + typedef A Alloc; + Alloc a; + std::allocator_traits::deallocate(a, reinterpret_cast(static_cast(0xDEADBEEF)), 10); + assert(called == 1); + } } diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp index 2ee64b8b4a07..1a812876bf0c 100644 --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/destroy.pass.cpp @@ -23,6 +23,7 @@ #include #include "test_macros.h" +#include "incomplete_type_helper.h" template struct A @@ -65,6 +66,13 @@ int main() std::allocator_traits >::destroy(a, (A0*)&a0); assert(A0::count == 1); } + { + typedef IncompleteHolder* VT; + typedef A Alloc; + Alloc a; + std::aligned_storage::type store; + std::allocator_traits::destroy(a, (VT*)&store); + } #if TEST_STD_VER >= 11 { A0::count = 0; diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/incomplete_type_helper.h b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/incomplete_type_helper.h new file mode 100644 index 000000000000..7662338d73c4 --- /dev/null +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/incomplete_type_helper.h @@ -0,0 +1,14 @@ +#ifndef TEST_INCOMPLETE_TYPE_HELPER_H +#define TEST_INCOMPLETE_TYPE_HELPER_H + +#include "min_allocator.h" + +namespace NS { + struct Incomplete; +} + +template struct Holder { T value; }; + +typedef Holder IncompleteHolder; + +#endif diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp index d2c9a9826e14..12c0d02227fa 100644 --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/max_size.pass.cpp @@ -22,6 +22,7 @@ #include #include "test_macros.h" +#include "incomplete_type_helper.h" template struct A @@ -51,6 +52,12 @@ int main() const B b = {}; assert(std::allocator_traits >::max_size(b) == 100); } + { + typedef IncompleteHolder* VT; + typedef B Alloc; + Alloc a; + assert(std::allocator_traits::max_size(a) == 100); + } #if TEST_STD_VER >= 11 { A a; diff --git a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp index 2e9703037894..8355db18276a 100644 --- a/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp +++ b/libcxx/test/std/utilities/memory/allocator.traits/allocator.traits.members/select_on_container_copy_construction.pass.cpp @@ -23,6 +23,7 @@ #include #include "test_macros.h" +#include "incomplete_type_helper.h" template struct A @@ -57,6 +58,12 @@ int main() const A a(0); assert(std::allocator_traits >::select_on_container_copy_construction(a).id == 0); } + { + typedef IncompleteHolder* VT; + typedef A Alloc; + Alloc a; + assert(std::allocator_traits::select_on_container_copy_construction(a).id == 0); + } #if TEST_STD_VER >= 11 { B b;