[clang] [llvm] [libcxx] [clang-tools-extra] [libc++] Allow running the test suite with optimizations (PR #68753)

Louis Dionne via cfe-commits cfe-commits at lists.llvm.org
Wed Nov 1 08:25:29 PDT 2023


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/68753

>From 9824ef111975386152173916c1fd6a85264be0a0 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Tue, 10 Oct 2023 16:35:11 -0700
Subject: [PATCH 1/3] [libc++] Allow running the test suite with optimizations

This patch adds a configuration of the libc++ test suite that enables
optimizations when building the tests. It also adds a new CI configuration
to exercise this on a regular basis. This is added in the context of [1],
which requires building with optimizations in order to hit the bug.

[1]: https://github.com/llvm/llvm-project/issues/68552
---
 libcxx/cmake/caches/Generic-optimized.cmake |  4 +++
 libcxx/utils/ci/buildkite-pipeline.yml      | 18 +++++++++++++
 libcxx/utils/ci/run-buildbot                |  5 ++++
 libcxx/utils/libcxx/test/params.py          | 28 ++++++++++++++++++++-
 4 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 libcxx/cmake/caches/Generic-optimized.cmake

diff --git a/libcxx/cmake/caches/Generic-optimized.cmake b/libcxx/cmake/caches/Generic-optimized.cmake
new file mode 100644
index 000000000000000..577a5de9f34c539
--- /dev/null
+++ b/libcxx/cmake/caches/Generic-optimized.cmake
@@ -0,0 +1,4 @@
+set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "")
+set(LIBCXX_TEST_PARAMS "optimization=speed" CACHE STRING "")
+set(LIBCXXABI_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
+set(LIBUNWIND_TEST_PARAMS "${LIBCXX_TEST_PARAMS}" CACHE STRING "")
diff --git a/libcxx/utils/ci/buildkite-pipeline.yml b/libcxx/utils/ci/buildkite-pipeline.yml
index ebfb35eee91e1ed..1b52d994081c46f 100644
--- a/libcxx/utils/ci/buildkite-pipeline.yml
+++ b/libcxx/utils/ci/buildkite-pipeline.yml
@@ -743,6 +743,24 @@ steps:
           limit: 2
     timeout_in_minutes: 120
 
+  - label: "Optimized build and test suite"
+    command: "libcxx/utils/ci/run-buildbot generic-optimized"
+    artifact_paths:
+      - "**/test-results.xml"
+      - "**/*.abilist"
+    env:
+        CC: "clang-${LLVM_HEAD_VERSION}"
+        CXX: "clang++-${LLVM_HEAD_VERSION}"
+        ENABLE_CLANG_TIDY: "On"
+    agents:
+      queue: "libcxx-builders"
+      os: "linux"
+    retry:
+      automatic:
+        - exit_status: -1  # Agent was lost
+          limit: 2
+    timeout_in_minutes: 120
+
   # Other non-testing CI jobs
   - label: "Benchmarks"
     command: "libcxx/utils/ci/run-buildbot benchmarks"
diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot
index a71318123db3b12..18243b44a3d745c 100755
--- a/libcxx/utils/ci/run-buildbot
+++ b/libcxx/utils/ci/run-buildbot
@@ -479,6 +479,11 @@ generic-abi-unstable)
     generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-abi-unstable.cmake"
     check-runtimes
 ;;
+generic-optimized)
+    clean
+    generate-cmake -C "${MONOREPO_ROOT}/libcxx/cmake/caches/Generic-optimized.cmake"
+    check-runtimes
+;;
 apple-system)
     clean
 
diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py
index 456794b9b1cce95..9452f179aea3fec 100644
--- a/libcxx/utils/libcxx/test/params.py
+++ b/libcxx/utils/libcxx/test/params.py
@@ -11,7 +11,7 @@
 from pathlib import Path
 
 from libcxx.test.dsl import *
-from libcxx.test.features import _isMSVC
+from libcxx.test.features import _isClang, _isAppleClang, _isGCC, _isMSVC
 
 
 _warningFlags = [
@@ -90,6 +90,21 @@ def getStdFlag(cfg, std):
         return "-std=" + fallbacks[std]
     return None
 
+def getSpeedOptimizationFlag(cfg):
+    if _isClang(cfg) or _isAppleClang(cfg) or _isGCC(cfg):
+        return "-O3"
+    elif _isMSVC(cfg):
+        return "/O2"
+    else:
+        raise RuntimeError("Can't figure out what compiler is used in the configuration")
+
+def getSizeOptimizationFlag(cfg):
+    if _isClang(cfg) or _isAppleClang(cfg) or _isGCC(cfg):
+        return "-Os"
+    elif _isMSVC(cfg):
+        return "/O1"
+    else:
+        raise RuntimeError("Can't figure out what compiler is used in the configuration")
 
 # fmt: off
 DEFAULT_PARAMETERS = [
@@ -121,6 +136,17 @@ def getStdFlag(cfg, std):
             AddCompileFlag(lambda cfg: getStdFlag(cfg, std)),
         ],
     ),
+    Parameter(
+        name="optimization",
+        choices=["none", "speed", "size"],
+        type=str,
+        help="The version of the standard to compile the test suite with.",
+        default="none",
+        actions=lambda opt: filter(None, [
+            AddCompileFlag(lambda cfg: getSpeedOptimizationFlag(cfg)) if opt == "speed" else None,
+            AddCompileFlag(lambda cfg: getSizeOptimizationFlag(cfg)) if opt == "size" else None,
+        ]),
+    ),
     Parameter(
         name="enable_modules",
         choices=["none", "clang", "clang-lsv"],

>From f799be39afed6b82d1942a87cea66a4d1192d765 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Wed, 1 Nov 2023 10:56:30 -0400
Subject: [PATCH 2/3] Fix incorrect help

---
 libcxx/utils/libcxx/test/params.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/utils/libcxx/test/params.py b/libcxx/utils/libcxx/test/params.py
index 9452f179aea3fec..9b284265f95c695 100644
--- a/libcxx/utils/libcxx/test/params.py
+++ b/libcxx/utils/libcxx/test/params.py
@@ -140,7 +140,7 @@ def getSizeOptimizationFlag(cfg):
         name="optimization",
         choices=["none", "speed", "size"],
         type=str,
-        help="The version of the standard to compile the test suite with.",
+        help="The optimization level to use when compiling the test suite.",
         default="none",
         actions=lambda opt: filter(None, [
             AddCompileFlag(lambda cfg: getSpeedOptimizationFlag(cfg)) if opt == "speed" else None,

>From fe134eb76136bbbeea4ece2b67e499a3d4cba45f Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Wed, 1 Nov 2023 11:21:19 -0400
Subject: [PATCH 3/3] Fix failing tests due to new/delete ellision

---
 .../support.dynamic/libcpp_deallocate.sh.cpp  | 17 +++++------
 .../new.size.replace.indirect.pass.cpp        |  3 +-
 .../new.size.replace.pass.cpp                 |  3 +-
 .../new.size_align.replace.indirect.pass.cpp  |  7 +++--
 ...ze_align_nothrow.replace.indirect.pass.cpp |  7 +++--
 .../new.size_align_nothrow.replace.pass.cpp   |  7 +++--
 ...new.size_nothrow.replace.indirect.pass.cpp |  3 +-
 .../new.size_nothrow.replace.pass.cpp         |  3 +-
 .../new.size.replace.pass.cpp                 |  3 +-
 ...ze_align_nothrow.replace.indirect.pass.cpp |  7 +++--
 ...new.size_nothrow.replace.indirect.pass.cpp |  3 +-
 .../func.wrap.func.con/F.pass.cpp             |  2 +-
 libcxx/test/support/count_new.h               |  5 ++++
 libcxx/test/support/escape.h                  | 28 +++++++++++++++++++
 14 files changed, 71 insertions(+), 27 deletions(-)
 create mode 100644 libcxx/test/support/escape.h

diff --git a/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp b/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp
index 3b33737466c7419..a2c53861caba036 100644
--- a/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp
+++ b/libcxx/test/libcxx/language.support/support.dynamic/libcpp_deallocate.sh.cpp
@@ -39,6 +39,7 @@
 #include <string>
 #include <cassert>
 
+#include "escape.h"
 #include "test_macros.h"
 
 TEST_DIAGNOSTIC_PUSH
@@ -192,13 +193,13 @@ void test_allocator_and_new_match() {
   stats.reset();
 #if defined(NO_SIZE) && defined(NO_ALIGN)
   {
-    int* x = new int(42);
+    int* x = support::escape(new int(42));
     delete x;
     assert(stats.expect_plain());
   }
   stats.reset();
   {
-    AlignedType* a = new AlignedType();
+    AlignedType* a = support::escape(new AlignedType());
     delete a;
     assert(stats.expect_plain());
   }
@@ -207,14 +208,14 @@ void test_allocator_and_new_match() {
   stats.reset();
 #if TEST_STD_VER >= 11
   {
-    int* x = new int(42);
+    int* x = support::escape(new int(42));
     delete x;
     assert(stats.expect_plain());
   }
 #endif
   stats.reset();
   {
-    AlignedType* a = new AlignedType();
+    AlignedType* a = support::escape(new AlignedType());
     delete a;
     assert(stats.expect_align(TEST_ALIGNOF(AlignedType)));
   }
@@ -222,13 +223,13 @@ void test_allocator_and_new_match() {
 #elif defined(NO_ALIGN)
   stats.reset();
   {
-    int* x = new int(42);
+    int* x = support::escape(new int(42));
     delete x;
     assert(stats.expect_size(sizeof(int)));
   }
   stats.reset();
   {
-    AlignedType* a = new AlignedType();
+    AlignedType* a = support::escape(new AlignedType());
     delete a;
     assert(stats.expect_size(sizeof(AlignedType)));
   }
@@ -236,13 +237,13 @@ void test_allocator_and_new_match() {
 #else
   stats.reset();
   {
-    int* x = new int(42);
+    int* x = support::escape(new int(42));
     delete x;
     assert(stats.expect_size(sizeof(int)));
   }
   stats.reset();
   {
-    AlignedType* a = new AlignedType();
+    AlignedType* a = support::escape(new AlignedType());
     delete a;
     assert(stats.expect_size_align(sizeof(AlignedType),
                                    TEST_ALIGNOF(AlignedType)));
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp
index 172b6cc2f2944ad..56264c25575847e 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.indirect.pass.cpp
@@ -20,6 +20,7 @@
 #include <cassert>
 #include <limits>
 
+#include "escape.h"
 #include "test_macros.h"
 
 int new_called = 0;
@@ -40,7 +41,7 @@ void operator delete(void* p) TEST_NOEXCEPT {
 
 int main(int, char**) {
     new_called = delete_called = 0;
-    int* x = new int[3];
+    int* x = support::escape(new int[3]);
     assert(x != nullptr);
     ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1);
 
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp
index e352c00b4d0af94..1612ecba96ac9b8 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size.replace.pass.cpp
@@ -19,6 +19,7 @@
 #include <cassert>
 #include <limits>
 
+#include "escape.h"
 #include "test_macros.h"
 
 int new_called = 0;
@@ -38,7 +39,7 @@ void operator delete[](void* p) TEST_NOEXCEPT {
 
 int main(int, char**) {
     new_called = delete_called = 0;
-    int* x = new int[3];
+    int* x = support::escape(new int[3]);
     assert(x != nullptr);
     ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1);
 
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp
index 64d987ed691b297..370aba01a2c819d 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align.replace.indirect.pass.cpp
@@ -29,6 +29,7 @@
 #include <cassert>
 #include <limits>
 
+#include "escape.h"
 #include "test_macros.h"
 #include "../types.h"
 
@@ -54,7 +55,7 @@ int main(int, char**) {
     // Test with an overaligned type
     {
         new_called = delete_called = 0;
-        OverAligned* x = new OverAligned[3];
+        OverAligned* x = support::escape(new OverAligned[3]);
         ASSERT_WITH_OPERATOR_NEW_FALLBACKS(static_cast<void*>(x) == DummyData);
         ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1);
 
@@ -65,7 +66,7 @@ int main(int, char**) {
     // Test with a type that is right on the verge of being overaligned
     {
         new_called = delete_called = 0;
-        MaxAligned* x = new MaxAligned[3];
+        MaxAligned* x = support::escape(new MaxAligned[3]);
         assert(x != nullptr);
         assert(new_called == 0);
 
@@ -76,7 +77,7 @@ int main(int, char**) {
     // Test with a type that is clearly not overaligned
     {
         new_called = delete_called = 0;
-        int* x = new int[3];
+        int* x = support::escape(new int[3]);
         assert(x != nullptr);
         assert(new_called == 0);
 
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp
index a62128942eaf638..12b77c4d33c9417 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.indirect.pass.cpp
@@ -29,6 +29,7 @@
 #include <cassert>
 #include <limits>
 
+#include "escape.h"
 #include "test_macros.h"
 #include "../types.h"
 
@@ -54,7 +55,7 @@ int main(int, char**) {
     // Test with an overaligned type
     {
         new_called = delete_called = 0;
-        OverAligned* x = new (std::nothrow) OverAligned[3];
+        OverAligned* x = support::escape(new (std::nothrow) OverAligned[3]);
         ASSERT_WITH_OPERATOR_NEW_FALLBACKS(static_cast<void*>(x) == DummyData);
         ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1);
 
@@ -65,7 +66,7 @@ int main(int, char**) {
     // Test with a type that is right on the verge of being overaligned
     {
         new_called = delete_called = 0;
-        MaxAligned* x = new (std::nothrow) MaxAligned[3];
+        MaxAligned* x = support::escape(new (std::nothrow) MaxAligned[3]);
         assert(x != nullptr);
         assert(new_called == 0);
 
@@ -76,7 +77,7 @@ int main(int, char**) {
     // Test with a type that is clearly not overaligned
     {
         new_called = delete_called = 0;
-        int* x = new (std::nothrow) int[3];
+        int* x = support::escape(new (std::nothrow) int[3]);
         assert(x != nullptr);
         assert(new_called == 0);
 
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp
index 9a830e0e82990aa..6e4b95a2eea213a 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_align_nothrow.replace.pass.cpp
@@ -26,6 +26,7 @@
 #include <cassert>
 #include <limits>
 
+#include "escape.h"
 #include "test_macros.h"
 #include "../types.h"
 
@@ -51,7 +52,7 @@ int main(int, char**) {
     // Test with an overaligned type
     {
         new_nothrow_called = delete_called = 0;
-        OverAligned* x = new (std::nothrow) OverAligned[3];
+        OverAligned* x = support::escape(new (std::nothrow) OverAligned[3]);
         assert(static_cast<void*>(x) == DummyData);
         ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_nothrow_called == 1);
 
@@ -62,7 +63,7 @@ int main(int, char**) {
     // Test with a type that is right on the verge of being overaligned
     {
         new_nothrow_called = delete_called = 0;
-        MaxAligned* x = new (std::nothrow) MaxAligned[3];
+        MaxAligned* x = support::escape(new (std::nothrow) MaxAligned[3]);
         assert(x != nullptr);
         assert(new_nothrow_called == 0);
 
@@ -73,7 +74,7 @@ int main(int, char**) {
     // Test with a type that is clearly not overaligned
     {
         new_nothrow_called = delete_called = 0;
-        int* x = new (std::nothrow) int[3];
+        int* x = support::escape(new (std::nothrow) int[3]);
         assert(x != nullptr);
         assert(new_nothrow_called == 0);
 
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp
index 8ad0292dcb5ca4b..2b481c21d5de01d 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.indirect.pass.cpp
@@ -24,6 +24,7 @@
 #include <cstdlib>
 #include <cassert>
 
+#include "escape.h"
 #include "test_macros.h"
 
 int new_called = 0;
@@ -44,7 +45,7 @@ void operator delete(void* p) TEST_NOEXCEPT {
 
 int main(int, char**) {
     new_called = delete_called = 0;
-    int* x = new (std::nothrow) int[3];
+    int* x = support::escape(new (std::nothrow) int[3]);
     assert(x != nullptr);
     ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1);
 
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp
index b85e15ce64b48ac..f06940ba3701855 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.array/new.size_nothrow.replace.pass.cpp
@@ -18,6 +18,7 @@
 #include <cstdlib>
 #include <cassert>
 
+#include "escape.h"
 #include "test_macros.h"
 
 int new_nothrow_called = 0;
@@ -35,7 +36,7 @@ void operator delete[](void* p) TEST_NOEXCEPT {
 
 int main(int, char**) {
     new_nothrow_called = delete_called = 0;
-    int* x = new (std::nothrow) int[3];
+    int* x = support::escape(new (std::nothrow) int[3]);
     assert(x != nullptr);
     ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_nothrow_called == 1);
 
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp
index a03313e5872ef3b..f992ad325c0068a 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size.replace.pass.cpp
@@ -17,6 +17,7 @@
 #include <cstdlib>
 #include <cassert>
 
+#include "escape.h"
 #include "test_macros.h"
 
 int new_called = 0;
@@ -36,7 +37,7 @@ void operator delete(void* p) TEST_NOEXCEPT {
 
 int main(int, char**) {
     new_called = delete_called = 0;
-    int* x = new int(3);
+    int* x = support::escape(new int(3));
     assert(x != nullptr);
     ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1);
 
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp
index 3cbb5aaf8f0be6d..6575dce91606f6c 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_align_nothrow.replace.indirect.pass.cpp
@@ -28,6 +28,7 @@
 #include <cassert>
 #include <limits>
 
+#include "escape.h"
 #include "test_macros.h"
 #include "../types.h"
 
@@ -53,7 +54,7 @@ int main(int, char**) {
     // Test with an overaligned type
     {
         new_called = delete_called = 0;
-        OverAligned* x = new (std::nothrow) OverAligned;
+        OverAligned* x = support::escape(new (std::nothrow) OverAligned);
         ASSERT_WITH_OPERATOR_NEW_FALLBACKS(static_cast<void*>(x) == DummyData);
         ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1);
 
@@ -64,7 +65,7 @@ int main(int, char**) {
     // Test with a type that is right on the verge of being overaligned
     {
         new_called = delete_called = 0;
-        MaxAligned* x = new (std::nothrow) MaxAligned;
+        MaxAligned* x = support::escape(new (std::nothrow) MaxAligned);
         assert(x != nullptr);
         assert(new_called == 0);
 
@@ -75,7 +76,7 @@ int main(int, char**) {
     // Test with a type that is clearly not overaligned
     {
         new_called = delete_called = 0;
-        int* x = new (std::nothrow) int;
+        int* x = support::escape(new (std::nothrow) int);
         assert(x != nullptr);
         assert(new_called == 0);
 
diff --git a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp
index 2ae0dfa4f1abc41..e38376a2ce96e06 100644
--- a/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp
+++ b/libcxx/test/std/language.support/support.dynamic/new.delete/new.delete.single/new.size_nothrow.replace.indirect.pass.cpp
@@ -19,6 +19,7 @@
 #include <cstdlib>
 #include <cassert>
 
+#include "escape.h"
 #include "test_macros.h"
 
 int new_called = 0;
@@ -39,7 +40,7 @@ void operator delete(void* p) TEST_NOEXCEPT {
 
 int main(int, char**) {
     new_called = delete_called = 0;
-    int* x = new (std::nothrow) int(3);
+    int* x = support::escape(new (std::nothrow) int(3));
     assert(x != nullptr);
     ASSERT_WITH_OPERATOR_NEW_FALLBACKS(new_called == 1);
 
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp
index c1ad528254af1a4..2c8e22941c999f8 100644
--- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/F.pass.cpp
@@ -69,7 +69,7 @@ int main(int, char**)
     {
     std::function<int(int)> f = A();
     assert(A::count == 1);
-    assert(globalMemCounter.checkOutstandingNewEq(1));
+    assert(globalMemCounter.checkOutstandingNewLessThanOrEqual(2));
     RTTI_ASSERT(f.target<A>());
     RTTI_ASSERT(f.target<int(*)(int)>() == 0);
     }
diff --git a/libcxx/test/support/count_new.h b/libcxx/test/support/count_new.h
index b6424850101625b..ef4306e520b195b 100644
--- a/libcxx/test/support/count_new.h
+++ b/libcxx/test/support/count_new.h
@@ -181,6 +181,11 @@ class MemCounter
         return disable_checking || n == outstanding_new;
     }
 
+    bool checkOutstandingNewLessThanOrEqual(int n) const
+    {
+        return disable_checking || outstanding_new <= n;
+    }
+
     bool checkOutstandingNewNotEq(int n) const
     {
         return disable_checking || n != outstanding_new;
diff --git a/libcxx/test/support/escape.h b/libcxx/test/support/escape.h
new file mode 100644
index 000000000000000..a5556418a8b2e88
--- /dev/null
+++ b/libcxx/test/support/escape.h
@@ -0,0 +1,28 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SUPPORT_ESCAPE_H
+#define SUPPORT_ESCAPE_H
+
+#include "test_macros.h"
+
+namespace support {
+// This function can be used to hide some objects from compiler optimizations.
+//
+// For example, this is useful to hide the result of a call to `new` and ensure
+// ensure that the compiler doesn't elide the call to new/delete. Otherwise,
+// elliding calls to new/delete is allowed by the Standard and compilers actually
+// do it when optimizations are enabled.
+template <class T>
+TEST_CONSTEXPR __attribute__((noinline)) T* escape(T* ptr) TEST_NOEXCEPT {
+  return ptr;
+}
+} // namespace support
+
+#endif // SUPPORT_ESCAPE_H



More information about the cfe-commits mailing list