1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
10 // UNSUPPORTED: no-exceptions
11
12 // If the invocation of any non-const member function of `iterator` exits via an
13 // exception, the iterator acquires a singular value.
14
15 #include <ranges>
16
17 #include <tuple>
18
19 #include "../types.h"
20
21 struct ThrowOnIncrementIterator {
22 int* it_;
23
24 using value_type = int;
25 using difference_type = std::intptr_t;
26 using iterator_concept = std::input_iterator_tag;
27
28 ThrowOnIncrementIterator() = default;
ThrowOnIncrementIteratorThrowOnIncrementIterator29 explicit ThrowOnIncrementIterator(int* it) : it_(it) {}
30
operator ++ThrowOnIncrementIterator31 ThrowOnIncrementIterator& operator++() {
32 ++it_;
33 throw 5;
34 return *this;
35 }
operator ++ThrowOnIncrementIterator36 void operator++(int) { ++it_; }
37
operator *ThrowOnIncrementIterator38 int& operator*() const { return *it_; }
39
40 friend bool operator==(ThrowOnIncrementIterator const&, ThrowOnIncrementIterator const&) = default;
41 };
42
43 struct ThrowOnIncrementView : IntBufferView {
beginThrowOnIncrementView44 ThrowOnIncrementIterator begin() const { return ThrowOnIncrementIterator{buffer_}; }
endThrowOnIncrementView45 ThrowOnIncrementIterator end() const { return ThrowOnIncrementIterator{buffer_ + size_}; }
46 };
47
48 // Cannot run the test at compile time because it is not allowed to throw exceptions
test()49 void test() {
50 int buffer[] = {1, 2, 3};
51 {
52 // zip iterator should be able to be destroyed after member function throws
53 std::ranges::zip_view v{ThrowOnIncrementView{buffer}};
54 auto it = v.begin();
55 try {
56 ++it;
57 assert(false); // should not be reached as the above expression should throw.
58 } catch (int e) {
59 assert(e == 5);
60 }
61 }
62
63 {
64 // zip iterator should be able to be assigned after member function throws
65 std::ranges::zip_view v{ThrowOnIncrementView{buffer}};
66 auto it = v.begin();
67 try {
68 ++it;
69 assert(false); // should not be reached as the above expression should throw.
70 } catch (int e) {
71 assert(e == 5);
72 }
73 it = v.begin();
74 auto [x] = *it;
75 assert(x == 1);
76 }
77 }
78
main(int,char **)79 int main(int, char**) {
80 test();
81
82 return 0;
83 }
84