xref: /llvm-project/clang/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.conv/p4.cpp (revision f8c5a68365fb82d9ffc64511f4b50b9c1e68144f)
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 
test_cvqual_ref(AnyT any)10 void test_cvqual_ref(AnyT any) {
11   const int &cir = any;
12 }
13 
14 struct AnyThreeLevelPtr {
15   template<typename T>
operator T***AnyThreeLevelPtr16   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 
test_deduce_with_qual(AnyThreeLevelPtr a3)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>
operator T Class::*AnyPtrMem36   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 
test_deduce_ptrmem_with_qual(AnyPtrMem apm)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>
operator T Class1::*Class2::*TwoLevelPtrMem52   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 
test_deduce_two_level_ptrmem_with_qual(TwoLevelPtrMem apm)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 {
operator Tnon_ptr_ref_cv_qual::ConvToT71     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 {
operator T&non_ptr_ref_cv_qual::ConvToTRef91     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 {
operator const Tnon_ptr_ref_cv_qual::ConvToConstT105     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 {
operator const T&non_ptr_ref_cv_qual::ConvToConstTRef115     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>
operator Arr<int,N>&non_ptr_ref_cv_qual::ConvToArr126     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   struct ConvToConstArr {
134     template <int N>
operator const Arr<int,N>&non_ptr_ref_cv_qual::ConvToConstArr135     operator const Arr<int, N> &() { // expected-note {{candidate}}
136       static_assert(N == 3, "");
137     }
138   };
139   Arr<int, 3> &test_conv_to_const_arr_1 = ConvToConstArr(); // expected-error {{no viable}}
140   const Arr<int, 3> &test_conv_to_const_arr_2 = ConvToConstArr(); // ok
141 
142 #if __cplusplus >= 201702L
143   template<bool Noexcept, typename T, typename ...U> using Function = T(U...) noexcept(Noexcept);
144   template<bool Noexcept> struct ConvToFunction {
145     template <typename T, typename ...U> operator Function<Noexcept, T, U...>&(); // expected-note {{candidate}}
146   };
147   void (&fn1)(int) noexcept(false) = ConvToFunction<false>();
148   void (&fn2)(int) noexcept(true)  = ConvToFunction<false>(); // expected-error {{no viable}}
149   void (&fn3)(int) noexcept(false) = ConvToFunction<true>();
150   void (&fn4)(int) noexcept(true)  = ConvToFunction<true>();
151 
152   struct ConvToFunctionDeducingNoexcept {
153     template <bool Noexcept, typename T, typename ...U> operator Function<Noexcept, T, U...>&();
154   };
155   void (&fn5)(int) noexcept(false) = ConvToFunctionDeducingNoexcept();
156   void (&fn6)(int) noexcept(true)  = ConvToFunctionDeducingNoexcept();
157 #endif
158 }
159