diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp --- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.append.pass.cpp @@ -195,9 +195,10 @@ // required. // On Windows, the append method is more complex and uses intermediate // path objects, which causes extra allocations. - // In DLL builds on Windows, the overridden operator new won't pick up - // allocations done within the DLL, so the RequireAllocationGuard below - // won't necessarily see allocations in the cases where they're expected. + // If the overridden operator new can't pick up allocations done within + // the library implementation, the RequireAllocationGuard below won't + // necessarily see allocations in the cases where they're expected, so + // set requireAtLeast(0) in those cases. #ifdef _WIN32 bool DisableAllocations = false; #else @@ -209,7 +210,7 @@ { RequireAllocationGuard g; // requires 1 or more allocations occur by default if (DisableAllocations) g.requireExactly(0); - else TEST_ONLY_WIN32_DLL(g.requireAtLeast(0)); + else WITHOUT_LIBRARY_INTERNAL_ALLOCATIONS(g.requireAtLeast(0)); LHS /= RHS; } assert(PathEq(LHS, E)); @@ -221,7 +222,7 @@ { RequireAllocationGuard g; if (DisableAllocations) g.requireExactly(0); - else TEST_ONLY_WIN32_DLL(g.requireAtLeast(0)); + else WITHOUT_LIBRARY_INTERNAL_ALLOCATIONS(g.requireAtLeast(0)); LHS.append(RHS, REnd); } assert(PathEq(LHS, E)); diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp --- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.assign/move.pass.cpp @@ -28,9 +28,7 @@ assert(globalMemCounter.checkOutstandingNewEq(0)); const std::string s("we really really really really really really really " "really really long string so that we allocate"); - // On windows, the operator new from count_new.h can't override the default - // operator for calls within the libc++ DLL. - TEST_NOT_WIN32_DLL(assert(globalMemCounter.checkOutstandingNewEq(1))); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkOutstandingNewEq(1)); const fs::path::string_type ps(s.begin(), s.end()); path p(s); { diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp --- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.concat.pass.cpp @@ -141,9 +141,10 @@ // For the path native type, no allocations will be performed because no // conversion is required. - // In DLL builds on Windows, the overridden operator new won't pick up - // allocations done within the DLL, so the RequireAllocationGuard below - // won't necessarily see allocations in the cases where they're expected. + // If the overridden operator new can't pick up allocations done within + // the library implementation, the RequireAllocationGuard below won't + // necessarily see allocations in the cases where they're expected, so + // set requireAtLeast(0) in those cases. bool DisableAllocations = std::is_same::value; { path LHS(L); PathReserve(LHS, ReserveSize); @@ -151,7 +152,7 @@ { RequireAllocationGuard g; // requires 1 or more allocations occur by default if (DisableAllocations) g.requireExactly(0); - else TEST_ONLY_WIN32_DLL(g.requireAtLeast(0)); + else WITHOUT_LIBRARY_INTERNAL_ALLOCATIONS(g.requireAtLeast(0)); LHS += RHS; } assert(LHS == E); @@ -163,7 +164,7 @@ { RequireAllocationGuard g; if (DisableAllocations) g.requireExactly(0); - else TEST_ONLY_WIN32_DLL(g.requireAtLeast(0)); + else WITHOUT_LIBRARY_INTERNAL_ALLOCATIONS(g.requireAtLeast(0)); LHS.concat(RHS, REnd); } assert(LHS == E); diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp --- a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/move.pass.cpp @@ -28,9 +28,7 @@ assert(globalMemCounter.checkOutstandingNewEq(0)); const std::string s("we really really really really really really really " "really really long string so that we allocate"); - // On windows, the operator new from count_new.h can't override the default - // operator for calls within the libc++ DLL. - TEST_NOT_WIN32_DLL(assert(globalMemCounter.checkOutstandingNewEq(1))); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkOutstandingNewEq(1)); const fs::path::string_type ps(s.begin(), s.end()); path p(s); { diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_align_val_t_nothrow_replace.pass.cpp @@ -62,9 +62,10 @@ void operator delete[](void* p, std::align_val_t a) TEST_NOEXCEPT { - assert(p == Buff); + (void)p; + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(p == Buff); assert(static_cast(a) == OverAligned); - assert(new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(new_called); --new_called; } @@ -74,18 +75,18 @@ A* ap = new (std::nothrow) A[2]; assert(ap); assert(A_constructed == 2); - assert(new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(new_called); delete [] ap; assert(A_constructed == 0); - assert(!new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(!new_called); } { B* bp = new (std::nothrow) B[2]; assert(bp); assert(B_constructed == 2); - assert(!new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(!new_called); delete [] bp; - assert(!new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(!new_called); assert(!B_constructed); } diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_nothrow_replace.pass.cpp --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_nothrow_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_nothrow_replace.pass.cpp @@ -50,11 +50,11 @@ DoNotOptimize(ap); assert(ap); assert(A_constructed == 3); - assert(new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(new_called); delete [] ap; DoNotOptimize(ap); assert(A_constructed == 0); - assert(!new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(!new_called); return 0; } diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_replace.pass.cpp --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new_array_replace.pass.cpp @@ -51,11 +51,11 @@ DoNotOptimize(ap); assert(ap); assert(A_constructed == 3); - assert(new_called == 1); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(new_called == 1); delete [] ap; DoNotOptimize(ap); assert(A_constructed == 0); - assert(new_called == 0); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(new_called == 0); return 0; } diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_align_val_t_nothrow_replace.pass.cpp @@ -62,9 +62,10 @@ void operator delete(void* p, std::align_val_t a) TEST_NOEXCEPT { - assert(p == Buff); + (void)p; + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(p == Buff); assert(static_cast(a) == OverAligned); - assert(new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(new_called); --new_called; } @@ -75,18 +76,18 @@ A* ap = new (std::nothrow) A; assert(ap); assert(A_constructed); - assert(new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(new_called); delete ap; assert(!A_constructed); - assert(!new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(!new_called); } { B* bp = new (std::nothrow) B; assert(bp); assert(B_constructed); - assert(!new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(!new_called); delete bp; - assert(!new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(!new_called); assert(!B_constructed); } diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_nothrow_replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_nothrow_replace.pass.cpp --- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_nothrow_replace.pass.cpp +++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new_nothrow_replace.pass.cpp @@ -50,11 +50,11 @@ DoNotOptimize(ap); assert(ap); assert(A_constructed); - assert(new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(new_called); delete ap; DoNotOptimize(ap); assert(!A_constructed); - assert(!new_called); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(!new_called); return 0; } diff --git a/libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp b/libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp --- a/libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp +++ b/libcxx/test/std/localization/locale.categories/category.ctype/facet.ctype.special/facet.ctype.char.dtor/dtor.pass.cpp @@ -37,9 +37,7 @@ new std::ctype(new std::ctype::mask[256], true)); assert(globalMemCounter.checkDeleteArrayCalledEq(0)); } - // On windows, the operator new from count_new.h can't override the default - // operator for calls within the libc++ DLL. - TEST_NOT_WIN32_DLL(assert(globalMemCounter.checkDeleteArrayCalledEq(1))); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkDeleteArrayCalledEq(1)); return 0; } diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp --- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp +++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.constr/F.pass.cpp @@ -136,7 +136,7 @@ for (int i=0; i <= numAllocs; ++i) { throw_one = i; f_run = false; - TEST_NOT_WIN32_DLL(unsigned old_outstanding = outstanding_new); + unsigned old_outstanding = outstanding_new; try { std::thread t(f); assert(i == numAllocs); // Only final iteration will not throw. @@ -146,9 +146,8 @@ assert(i < numAllocs); assert(!f_run); // (2.2) } - // In DLL builds on Windows, the overridden operators new/delete won't - // override calls from within the DLL, so this won't match. - TEST_NOT_WIN32_DLL(assert(old_outstanding == outstanding_new)); // (2.3) + (void)old_outstanding; + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(old_outstanding == outstanding_new); // (2.3) } f_run = false; throw_one = 0xFFF; diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h --- a/libcxx/test/support/test_macros.h +++ b/libcxx/test/support/test_macros.h @@ -381,12 +381,40 @@ #define TEST_NOT_WIN32(...) __VA_ARGS__ #endif -#if defined(_WIN32) && !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) -#define TEST_NOT_WIN32_DLL(...) ((void)0) -#define TEST_ONLY_WIN32_DLL(...) __VA_ARGS__ +#if (defined(_WIN32) && !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)) || defined(__MVS__) +// 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. +#define ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(...) ((void)0) +#define WITHOUT_LIBRARY_INTERNAL_ALLOCATIONS(...) __VA_ARGS__ +#else +#define ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(...) assert(__VA_ARGS__) +#define WITHOUT_LIBRARY_INTERNAL_ALLOCATIONS(...) ((void)0) +#endif + +#if (defined(_WIN32) && !defined(_MSC_VER) && !defined(_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)) || 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)0) #else -#define TEST_NOT_WIN32_DLL(...) __VA_ARGS__ -#define TEST_ONLY_WIN32_DLL(...) ((void)0) +#define ASSERT_WITH_OPERATOR_NEW_FALLBACKS(...) assert(__VA_ARGS__) #endif #ifdef _WIN32