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
10
11 // ITER_TRAITS(I)
12
13 // -- If the qualified-id ITER_TRAITS(I)::iterator_concept is valid and names a
14 // type, then ITER_CONCEPT(I) denotes that type.
15 // (1.2) -- Otherwise, if the qualified-id ITER_TRAITS(I)::iterator_category is
16 // valid and names a type, then ITER_CONCEPT(I) denotes that type.
17 // (1.3) -- Otherwise, if iterator_traits<I> names a specialization generated
18 // from the primary template, then ITER_CONCEPT(I) denotes
19 // random_access_iterator_tag.
20 // (1.4) -- Otherwise, ITER_CONCEPT(I) does not denote a type.
21
22 #include "test_macros.h"
23
24 #include <iterator>
25 struct OtherTag : std::input_iterator_tag {};
26 struct OtherTagTwo : std::output_iterator_tag {};
27
28 struct MyIter {
29 using iterator_category = std::random_access_iterator_tag;
30 using iterator_concept = int;
31 using value_type = char;
32 using difference_type = std::ptrdiff_t;
33 using pointer = char*;
34 using reference = char&;
35 };
36
37 struct MyIter2 {
38 using iterator_category = OtherTag;
39 using value_type = char;
40 using difference_type = std::ptrdiff_t;
41 using pointer = char*;
42 using reference = char&;
43 };
44
45 struct MyIter3 {};
46
47 struct Empty {};
48 struct EmptyWithSpecial {};
49 template <>
50 struct std::iterator_traits<MyIter3> {
51 using iterator_category = OtherTagTwo;
52 using value_type = char;
53 using difference_type = std::ptrdiff_t;
54 using pointer = char*;
55 using reference = char&;
56 };
57
58 template <>
59 struct std::iterator_traits<EmptyWithSpecial> {
60 // empty non-default.
61 };
62
main(int,char **)63 int main(int, char**) {
64 // If the qualified-id ITER_TRAITS(I)::iterator_concept is valid and names a type,
65 // then ITER_CONCEPT(I) denotes that type.
66 {
67 #if TEST_STD_VER > 17
68 ASSERT_SAME_TYPE(std::_ITER_CONCEPT<char*>, std::contiguous_iterator_tag);
69 #endif
70 ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter>, int);
71 }
72 // Otherwise, if the qualified-id ITER_TRAITS(I)::iterator_category is valid
73 // and names a type, then ITER_CONCEPT(I) denotes that type.
74 {
75 ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter2>, OtherTag);
76 ASSERT_SAME_TYPE(std::_ITER_CONCEPT<MyIter3>, OtherTagTwo);
77 }
78 // FIXME - This requirement makes no sense to me. Why does an empty type with
79 // an empty default iterator_traits get a category of random?
80 {
81 ASSERT_SAME_TYPE(std::_ITER_CONCEPT<Empty>, std::random_access_iterator_tag);
82 }
83 {
84 static_assert(!std::_IsValidExpansion<std::_ITER_CONCEPT, EmptyWithSpecial>::value, "");
85 }
86
87 return 0;
88 }
89