1 | // RUN: %clang_cc1 -fsyntax-only %s -verify |
2 | // RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -verify |
3 | // RUN: %clang_cc1 -std=c++17 -fsyntax-only %s -verify |
4 | |
5 | struct AnyT { |
6 | template<typename T> |
7 | operator T(); |
8 | }; |
9 | |
10 | void test_cvqual_ref(AnyT any) { |
11 | const int &cir = any; |
12 | } |
13 | |
14 | struct AnyThreeLevelPtr { |
15 | template<typename T> |
16 | operator T***() const { |
17 | T x = 0; // expected-note 2{{declared const here}} |
18 | x = 0; // expected-error 2{{const-qualified type}} |
19 | T ***p; |
20 | return p; |
21 | } |
22 | }; |
23 | |
24 | struct X { }; |
25 | |
26 | void test_deduce_with_qual(AnyThreeLevelPtr a3) { |
27 | int * const * const * const ip1 = a3; |
28 | // FIXME: This is wrong; we are supposed to deduce 'T = int' here. |
29 | const int * const * const * const ip2 = a3; // expected-note {{instantiation of}} |
30 | // This one is correct, though. |
31 | const double * * * ip3 = a3; // expected-note {{instantiation of}} |
32 | } |
33 | |
34 | struct AnyPtrMem { |
35 | template<typename Class, typename T> |
36 | operator T Class::*() const |
37 | { |
38 | // This is correct: we don't need a qualification conversion here, so we |
39 | // deduce 'T = const float'. |
40 | T x = 0; // expected-note {{declared const here}} |
41 | x = 0; // expected-error {{const-qualified type}} |
42 | return 0; |
43 | } |
44 | }; |
45 | |
46 | void test_deduce_ptrmem_with_qual(AnyPtrMem apm) { |
47 | const float X::* pm = apm; // expected-note {{instantiation of}} |
48 | } |
49 | |
50 | struct TwoLevelPtrMem { |
51 | template<typename Class1, typename Class2, typename T> |
52 | operator T Class1::*Class2::*() const |
53 | { |
54 | T x = 0; // expected-note 2{{declared const here}} |
55 | x = 0; // expected-error 2{{const-qualified type}} |
56 | return 0; |
57 | } |
58 | }; |
59 | |
60 | void test_deduce_two_level_ptrmem_with_qual(TwoLevelPtrMem apm) { |
61 | // FIXME: This is wrong: we should deduce T = 'float' |
62 | const float X::* const X::* pm2 = apm; // expected-note {{instantiation of}} |
63 | // This is correct: we don't need a qualification conversion, so we directly |
64 | // deduce T = 'const double' |
65 | const double X::* X::* pm1 = apm; // expected-note {{instantiation of}} |
66 | } |
67 | |
68 | namespace non_ptr_ref_cv_qual { |
69 | template<typename Expected> |
70 | struct ConvToT { |
71 | template<typename T> operator T() { |
72 | using Check = T; |
73 | using Check = Expected; |
74 | } |
75 | }; |
76 | const int test_conv_to_t_1 = ConvToT<int>(); |
77 | // We intentionally deviate from [temp.deduct.conv]p4 here, and also remove |
78 | // the top-level cv-quaifiers from A *after* removing the reference type, if |
79 | // P is not also a reference type. This matches what other compilers are |
80 | // doing, and is necessary to support real-world code. |
81 | const int &test_conv_to_t_2 = ConvToT<int>(); |
82 | |
83 | // Example code that would be broken by the standard's rule. |
84 | struct Dest {}; |
85 | Dest d1a((ConvToT<Dest>())); |
86 | Dest d1b = ConvToT<Dest>(); |
87 | Dest &d2 = (d1a = ConvToT<Dest>()); |
88 | |
89 | template<typename Expected> |
90 | struct ConvToTRef { |
91 | template<typename T> operator T&() { |
92 | using Check = T; |
93 | using Check = Expected; |
94 | } |
95 | }; |
96 | const int test_conv_to_t_ref_1 = ConvToTRef<int>(); |
97 | const int &test_conv_to_t_ref_2 = ConvToTRef<const int>(); |
98 | |
99 | Dest d3a((ConvToTRef<const Dest>())); // initialize the copy ctor parameter with 'const Dest&' |
100 | Dest d3b = ConvToTRef<Dest>(); // convert to non-const T via [over.match.copy]/1.2 |
101 | Dest &d4 = (d3a = ConvToTRef<const Dest>()); |
102 | |
103 | template<typename Expected> |
104 | struct ConvToConstT { |
105 | template<typename T> operator const T() { |
106 | using Check = T; |
107 | using Check = Expected; |
108 | } |
109 | }; |
110 | const int test_conv_to_const_t_1 = ConvToConstT<int>(); |
111 | const int &test_conv_to_const_t_2 = ConvToConstT<int>(); |
112 | |
113 | template<typename Expected> |
114 | struct ConvToConstTRef { |
115 | template<typename T> operator const T&() { |
116 | using Check = T; |
117 | using Check = Expected; |
118 | } |
119 | }; |
120 | const int test_conv_to_const_t_ref_1 = ConvToConstTRef<int>(); |
121 | const int &test_conv_to_const_t_ref_2 = ConvToConstTRef<int>(); |
122 | |
123 | template <typename T, int N> using Arr = T[N]; |
124 | struct ConvToArr { |
125 | template <int N> |
126 | operator Arr<int, N> &() { |
127 | static_assert(N == 3, ""); |
128 | } |
129 | }; |
130 | int (&test_conv_to_arr_1)[3] = ConvToArr(); // ok |
131 | const int (&test_conv_to_arr_2)[3] = ConvToArr(); // ok, with qualification conversion |
132 | |
133 | #if __cplusplus >= 201702L |
134 | template<bool Noexcept, typename T, typename ...U> using Function = T(U...) noexcept(Noexcept); |
135 | template<bool Noexcept> struct ConvToFunction { |
136 | template <typename T, typename ...U> operator Function<Noexcept, T, U...>&(); // expected-note {{candidate}} |
137 | }; |
138 | void (&fn1)(int) noexcept(false) = ConvToFunction<false>(); |
139 | void (&fn2)(int) noexcept(true) = ConvToFunction<false>(); // expected-error {{no viable}} |
140 | void (&fn3)(int) noexcept(false) = ConvToFunction<true>(); |
141 | void (&fn4)(int) noexcept(true) = ConvToFunction<true>(); |
142 | |
143 | struct ConvToFunctionDeducingNoexcept { |
144 | template <bool Noexcept, typename T, typename ...U> operator Function<Noexcept, T, U...>&(); |
145 | }; |
146 | void (&fn5)(int) noexcept(false) = ConvToFunctionDeducingNoexcept(); |
147 | void (&fn6)(int) noexcept(true) = ConvToFunctionDeducingNoexcept(); |
148 | #endif |
149 | } |
150 | |