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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
| // RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++14 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++1z %s
// RUN: %clang_cc1 -fsyntax-only -verify %s
// C++0x [temp.arg.nontype] p5:
// The following conversions are performed on each expression used as
// a non-type template-argument. If a non-type template-argument cannot be
// converted to the type of the corresponding template-parameter then the
// program is ill-formed.
// -- for a non-type template-parameter of integral or enumeration type,
// integral promotions (4.5) and integral conversions (4.7) are applied.
namespace integral_parameters {
template<short s> struct X0 { };
X0<17> x0i;
X0<'a'> x0c;
template<char c> struct X1 { };
X1<100l> x1l;
}
// -- for a non-type template-parameter of type pointer to object,
// qualification conversions (4.4) and the array-to-pointer conversion
// (4.2) are applied; if the template-argument is of type
// std::nullptr_t, the null pointer conversion (4.10) is applied.
namespace pointer_to_object_parameters {
// PR6226
struct Str {
Str(const char *);
};
template<const char *s>
struct A {
Str get() { return s; }
};
char hello[6] = "Hello";
extern const char world[6];
const char world[6] = "world";
void test() {
(void)A<hello>().get();
(void)A<world>().get();
}
class X {
public:
X();
X(int, int);
operator int() const;
};
template<X const *Ptr> struct A2; // expected-note 0-1{{template parameter is declared here}}
X *X_ptr; // expected-note 0-1{{declared here}}
X an_X;
X array_of_Xs[10];
A2<X_ptr> *a12;
#if __cplusplus < 201103L
// expected-error@-2 {{must have its address taken}}
#else
// expected-error@-4 {{not a constant expression}} expected-note@-4 {{read of non-constexpr variable}}
#endif
A2<array_of_Xs> *a13;
A2<&an_X> *a13_2;
A2<(&an_X)> *a13_3;
#if __cplusplus < 201103L
// expected-warning@-2 {{address non-type template argument cannot be surrounded by parentheses}}
#endif
// PR6244
struct X1 {} X1v;
template <X1*> struct X2 { };
template <X1* Value> struct X3 : X2<Value> { };
struct X4 : X3<&X1v> { };
// PR6563
int *bar; // expected-note 0-1{{declared here}}
template <int *> struct zed {}; // expected-note 0-2{{template parameter is declared here}}
void g(zed<bar>*);
#if __cplusplus < 201103L
// expected-error@-2 {{must have its address taken}}
#else
// expected-error@-4 {{not a constant expression}} expected-note@-4 {{read of non-constexpr variable}}
#endif
int baz; // expected-note 0-1{{declared here}}
void g2(zed<baz>*);
#if __cplusplus < 201103L
// expected-error@-2 {{must have its address taken}}
#elif __cplusplus <= 201402L
// expected-error@-4 {{not a constant expression}} expected-note@-4 {{read of non-const variable}}
#else
// expected-error@-6 {{not implicitly convertible to 'int *'}}
#endif
void g3(zed<&baz>*); // okay
}
// -- For a non-type template-parameter of type reference to object, no
// conversions apply. The type referred to by the reference may be more
// cv-qualified than the (otherwise identical) type of the
// template-argument. The template-parameter is bound directly to the
// template-argument, which shall be an lvalue.
namespace reference_parameters {
template <int& N> struct S0 { }; // expected-note 0-3{{template parameter is declared here}}
template <const int& N> struct S1 { }; // expected-note 0-2{{template parameter is declared here}}
template <volatile int& N> struct S2 { }; // expected-note 0-2{{template parameter is declared here}}
template <const volatile int& N> struct S3 { };
int i;
extern const int ci;
volatile int vi;
extern const volatile int cvi;
void test() {
S0<i> s0;
S0<ci> s0c; // expected-error{{type 'const int'}}
S0<vi> s0v; // expected-error{{type 'volatile int'}}
S0<cvi> s0cv; // expected-error{{type 'const volatile int'}}
S1<i> s1;
S1<ci> s1c;
S1<vi> s1v; // expected-error{{type 'volatile int'}}
S1<cvi> s1cv; // expected-error{{type 'const volatile int'}}
S2<i> s2;
S2<ci> s2c; // expected-error{{type 'const int'}}
S2<vi> s2v;
S2<cvi> s2cv; // expected-error{{type 'const volatile int'}}
S3<i> s3;
S3<ci> s3c;
S3<vi> s3v;
S3<cvi> s3cv;
}
namespace PR6250 {
template <typename T, const T &ref> void inc() {
ref++; // expected-error{{read-only variable is not assignable}}
}
template<typename T, const T &ref> void bind() {
T &ref2 = ref; // expected-error{{drops 'const' qualifier}}
}
int counter;
void test() {
inc<int, counter>(); // expected-note{{instantiation of}}
bind<int, counter>(); // expected-note{{instantiation of}}
}
}
namespace PR6749 {
template <int& i> struct foo {}; // expected-note 0-1{{template parameter is declared here}}
int x, &y = x;
foo<y> f;
#if __cplusplus <= 201402L
// expected-error@-2 {{is not an object}}
#endif
}
}
// -- For a non-type template-parameter of type pointer to function, the
// function-to-pointer conversion (4.3) is applied; if the
// template-argument is of type std::nullptr_t, the null pointer
// conversion (4.10) is applied. If the template-argument represents
// a set of overloaded functions (or a pointer to such), the matching
// function is selected from the set (13.4).
namespace pointer_to_function {
template<int (*)(int)> struct X0 { }; // expected-note 0-3{{template parameter is declared here}}
int f(int);
int f(float);
int g(float);
int (*funcptr)(int); // expected-note 0-1{{declared here}}
void x0a(X0<f>);
void x0b(X0<&f>);
void x0c(X0<g>); // expected-error-re{{type 'int (float)' {{.*}}convert{{.*}} 'int (*)(int)'}}
void x0d(X0<&g>); // expected-error-re{{type 'int (*)(float)' {{.*}}convert{{.*}} 'int (*)(int)'}}
void x0e(X0<funcptr>);
#if __cplusplus < 201103L
// expected-error@-2 {{must have its address taken}}
#else
// expected-error@-4 {{not a constant expression}} expected-note@-4 {{read of non-constexpr variable}}
#endif
}
// -- For a non-type template-parameter of type reference to function, no
// conversions apply. If the template-argument represents a set of
// overloaded functions, the matching function is selected from the set
// (13.4).
namespace reference_to_function {
template<int (&)(int)> struct X0 { }; // expected-note 0-4{{template parameter is declared here}}
int f(int);
int f(float);
int g(float);
int (*funcptr)(int);
void x0a(X0<f>);
#if __cplusplus <= 201402L
void x0b(X0<&f>); // expected-error{{address taken in non-type template argument for template parameter of reference type 'int (&)(int)'}}
void x0c(X0<g>); // expected-error{{non-type template parameter of reference type 'int (&)(int)' cannot bind to template argument of type 'int (float)'}}
void x0d(X0<&g>); // expected-error{{address taken in non-type template argument for template parameter of reference type 'int (&)(int)'}}
void x0e(X0<funcptr>); // expected-error{{non-type template parameter of reference type 'int (&)(int)' cannot bind to template argument of type 'int (*)(int)'}}
#else
void x0b(X0<&f>); // expected-error{{value of type '<overloaded function type>' is not implicitly convertible to 'int (&)(int)'}}
void x0c(X0<g>); // expected-error{{value of type 'int (float)' is not implicitly convertible to 'int (&)(int)'}}
void x0d(X0<&g>); // expected-error{{value of type 'int (*)(float)' is not implicitly convertible to 'int (&)(int)'}}
void x0e(X0<funcptr>); // expected-error{{value of type 'int (*)(int)' is not implicitly convertible to 'int (&)(int)'}}
#endif
}
// -- For a non-type template-parameter of type pointer to member function,
// if the template-argument is of type std::nullptr_t, the null member
// pointer conversion (4.11) is applied; otherwise, no conversions
// apply. If the template-argument represents a set of overloaded member
// functions, the matching member function is selected from the set
// (13.4).
namespace pointer_to_member_function {
struct X { };
struct Y : X {
int f(int);
int g(int);
int g(float);
float h(float);
};
template<int (Y::*)(int)> struct X0 {}; // expected-note 0-1{{template parameter is declared here}}
X0<&Y::f> x0a;
X0<&Y::g> x0b;
X0<&Y::h> x0c; // expected-error-re{{type 'float (pointer_to_member_function::Y::*)(float){{( __attribute__\(\(thiscall\)\))?}}' {{.*}} convert{{.*}} 'int (pointer_to_member_function::Y::*)(int){{( __attribute__\(\(thiscall\)\))?}}'}}
}
// -- For a non-type template-parameter of type pointer to data member,
// qualification conversions (4.4) are applied; if the template-argument
// is of type std::nullptr_t, the null member pointer conversion (4.11)
// is applied.
namespace pointer_to_member_data {
struct X { int x; };
struct Y : X { int y; };
template<int Y::*> struct X0 {}; // expected-note 0-1{{template parameter is declared here}}
X0<&Y::y> x0a;
X0<&Y::x> x0b;
#if __cplusplus <= 201402L
// expected-error@-2 {{non-type template argument of type 'int pointer_to_member_data::X::*' cannot be converted to a value of type 'int pointer_to_member_data::Y::*'}}
#else
// expected-error@-4 {{conversion from 'int pointer_to_member_data::X::*' to 'int pointer_to_member_data::Y::*' is not allowed in a converted constant expression}}
#endif
// Test qualification conversions
template<const int Y::*> struct X1 {};
X1<&Y::y> x1a;
}
|