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 | // Test the set of C++11 features that Clang provides as an extension in C++03 mode. |
10 | // The language features we expect are: |
11 | // |
12 | // 1. rvalue references (and perfect forwarding) |
13 | // 2. variadic templates |
14 | // 3. alias templates |
15 | // 4. defaulted and deleted functions. |
16 | // 5. default values for non-type template parameters. |
17 | // |
18 | // Some features we don't get and can't be used in extended C++03 mode: |
19 | // |
20 | // 1. noexcept and constexpr |
21 | // 2. Two closing '>' without a space. |
22 | |
23 | #include <type_traits> |
24 | #include <cassert> |
25 | |
26 | // Equals delete and default are allowed in minimal C++03 mode. |
27 | namespace test_eq_delete_and_default { |
28 | void t1() = delete; |
29 | struct T2 { |
30 | T2() = default; |
31 | T2(T2 const&) = delete; |
32 | }; |
33 | } |
34 | |
35 | namespace alias_templates { |
36 | template <class T> |
37 | using X = T; |
38 | static_assert((std::is_same<X<int>, int>::value), "" ); |
39 | } |
40 | |
41 | namespace variadics_templates { |
42 | template <class ...Args> |
43 | int t1(Args...) { |
44 | return sizeof...(Args); |
45 | } |
46 | void test() { |
47 | assert(t1() == 0); |
48 | assert(t1(42) == 1); |
49 | assert(t1(1, 2, 3) == 3); |
50 | } |
51 | } |
52 | |
53 | namespace rvalue_references_move_semantics { |
54 | struct T { |
55 | T() : moved(0) {} |
56 | T(T const& other) : moved(other.moved) {} |
57 | T(T&& other) : moved(other.moved) { ++moved; other.moved = -1; } |
58 | int moved; |
59 | }; |
60 | void f(T o, int expect_moved) { assert(o.moved == expect_moved); } |
61 | void test() { |
62 | { |
63 | T t; |
64 | assert(t.moved == 0); |
65 | T t2(static_cast<T&&>(t)); |
66 | assert(t2.moved == 1); |
67 | assert(t.moved == -1); |
68 | } |
69 | { |
70 | T t; |
71 | f(o: t, expect_moved: 0); |
72 | f(o: static_cast<T&&>(t), expect_moved: 1); |
73 | } |
74 | } |
75 | } |
76 | |
77 | namespace rvalue_references_perfect_forwarding { |
78 | template <class Expect, class T> |
79 | void f(T&&) { |
80 | static_assert((std::is_same<Expect, T&&>::value), "" ); |
81 | } |
82 | void test() { |
83 | int x = 42; |
84 | f<int&>(x); |
85 | f<int&&>(42); |
86 | f<int&&>(static_cast<int&&>(x)); |
87 | } |
88 | } |
89 | |
90 | namespace default_values_for_nttp { |
91 | template <int I = 42> |
92 | void f() { assert(I == 42); } |
93 | void test() { |
94 | f(); |
95 | } |
96 | } |
97 | |
98 | namespace reference_qualified_functions { |
99 | struct T { |
100 | T() : lvalue_called(0), rvalue_called(0) {} |
101 | void foo() const & { lvalue_called++; } |
102 | void foo() && { rvalue_called++; } |
103 | mutable int lvalue_called; |
104 | int rvalue_called; |
105 | }; |
106 | |
107 | void test() { |
108 | { |
109 | T t; |
110 | t.foo(); |
111 | assert(t.lvalue_called == 1); |
112 | assert(t.rvalue_called == 0); |
113 | } |
114 | { |
115 | T t; |
116 | static_cast<T&&>(t).foo(); |
117 | assert(t.lvalue_called == 0); |
118 | assert(t.rvalue_called == 1); |
119 | } |
120 | } |
121 | } |
122 | |
123 | int main(int, char**) { |
124 | variadics_templates::test(); |
125 | rvalue_references_move_semantics::test(); |
126 | rvalue_references_perfect_forwarding::test(); |
127 | default_values_for_nttp::test(); |
128 | reference_qualified_functions::test(); |
129 | return 0; |
130 | } |
131 | |