[libcxx-commits] [libcxx] [libc++] Add exception guard for vector<bool>::__init_with_sentinel (PR #115491)

Peng Liu via libcxx-commits libcxx-commits at lists.llvm.org
Tue Nov 26 20:09:09 PST 2024


================
@@ -0,0 +1,87 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 EXCEPTION_TEST_HELPERS_H
+#define EXCEPTION_TEST_HELPERS_H
+
+#include "count_new.h"
+
+template <class T>
+struct throwing_allocator {
+  using value_type      = T;
+  using is_always_equal = std::false_type;
----------------
winner245 wrote:

Thank you for this comment, which motivated me to think more deeply about the issue. I just realized that I must have misunderstood the question initially. Now I believe the question pertains to the line `using is_always_equal = std::false_type;`, which appears counter-intuitive for a stateless allocator class. 

This line was in the original class `Allocator` before my refactor, my best guess is that the original author intended to use this class to test the exception safety for the constructor `vector(vector&&, const allocator_type&)` in `vector/vector.cons/exceptions.pass.cpp`: 

```cpp
try { // Throw in vector(vector&&, const allocator_type&) from type
    std::vector<ThrowingT, Allocator<ThrowingT> > vec(Allocator<ThrowingT>(false));
    int throw_after = 1;
    vec.emplace_back(throw_after);
    std::vector<ThrowingT, Allocator<ThrowingT> > vec2(std::move(vec), Allocator<ThrowingT>(false));
  } catch (int) {
  }
  check_new_delete_called();
```

This test aims to verify the exception safety for the constructor while performing an O(n) element-wise move (rather than the O(1) resource stealing), which requires the instances of the Allocator class to compare unequal. However, merely  setting `Allocator::is_always_equal::value` to false does not ensure that the instances of this class are unequal, which renders the above test actually testing nothing, as you also confirmed [here](https://github.com/llvm/llvm-project/pull/116449#pullrequestreview-2462660650). 
 

Beyond this scenario, I couldn't find any reason why we might need this member type. I believe we can safely remove it. Would you suggest I remove it in this PR or in my next one while rebasing?

https://github.com/llvm/llvm-project/pull/115491


More information about the libcxx-commits mailing list