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: libcpp-has-no-incomplete-ranges, 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; 29 explicit ThrowOnIncrementIterator(int* it) : it_(it) {} 30 31 ThrowOnIncrementIterator& operator++() { 32 ++it_; 33 throw 5; 34 return *this; 35 } 36 void operator++(int) { ++it_; } 37 38 int& operator*() const { return *it_; } 39 40 friend bool operator==(ThrowOnIncrementIterator const&, ThrowOnIncrementIterator const&) = default; 41 }; 42 43 struct ThrowOnIncrementView : IntBufferView { 44 ThrowOnIncrementIterator begin() const { return ThrowOnIncrementIterator{buffer_}; } 45 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 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 79 int main(int, char**) { 80 test(); 81 82 return 0; 83 } 84