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