p2.cpp
7.48 KB
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
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct X0 {
X0();
X0(int);
X0 f1();
X0 f2();
typedef int A;
typedef X0 B;
};
template<typename T>
struct X1 : X0 {
X1();
X1<T>(int);
(X1<T>)(float);
X1 f2();
X1 f2(int);
X1 f2(float);
X1 f2(double);
X1 f2(short);
X1 f2(long);
};
// Error recovery: out-of-line constructors whose names have template arguments.
template<typename T> X1<T>::X1<T>(int) { } // expected-error{{out-of-line constructor for 'X1' cannot have template arguments}}
template<typename T> (X1<T>::X1<T>)(float) { } // expected-error{{out-of-line constructor for 'X1' cannot have template arguments}}
// Error recovery: out-of-line constructor names intended to be types
X0::X0 X0::f1() { return X0(); } // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
struct X0::X0 X0::f2() { return X0(); }
template<typename T> X1<T>::X1<T> X1<T>::f2() { } // expected-error{{missing 'typename'}}
template<typename T> X1<T>::X1<T> (X1<T>::f2)(int) { } // expected-error{{missing 'typename'}}
template<typename T> struct X1<T>::X1<T> (X1<T>::f2)(float) { }
template<typename T> struct X1<T>::X1 (X1<T>::f2)(double) { }
template<typename T> typename X1<T>::template X1<T> X1<T>::f2(short) { } // expected-warning {{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
template<typename T> typename X1<T>::template X1<T> (X1<T>::f2)(long) { } // expected-warning {{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
void x1test(X1<int> x1i) {
x1i.f2();
x1i.f2(0);
x1i.f2(0.f);
x1i.f2(0.);
}
void other_contexts() {
X0::X0 x0; // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
X1<int>::X1 x1a; // expected-error{{qualified reference to 'X1' is a constructor name rather than a type in this context}}
X1<int>::X1<float> x1b; // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
X0::B ok1;
X0::X0::A ok2;
X0::X0::X0 x0b; // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
X1<int>::X0 ok3;
X1<int>::X0::X0 x0c; // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
X1<int>::X1<float>::X0 ok4;
{
typename X0::X0 tn1; // expected-warning{{qualified reference to 'X0' is a constructor name rather than a type in this context}} expected-warning 0-1{{typename}}
typename X1<int>::X1<float> tn2; // expected-warning{{qualified reference to 'X1' is a constructor name rather than a template name in this context}} expected-warning 0-1{{typename}}
typename X0::B ok1; // expected-warning 0-1{{typename}}
typename X1<int>::X0 ok2; // expected-warning 0-1{{typename}}
}
{
struct X0::X0 tag1;
struct X1<int>::X1 tag2;
struct X1<int>::X1<int> tag3;
}
int a;
{
X0::X0(a); // expected-error{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
// expected-warning@-1 {{redundant parentheses around declaration of variable named 'a'}} expected-note@-1 2{{}}
}
}
template<typename T> void in_instantiation_x0() {
typename T::X0 x0; // expected-warning{{qualified reference to 'X0' is a constructor name rather than a type in this context}}
typename T::A a;
typename T::B b;
}
template void in_instantiation_x0<X0>(); // expected-note {{instantiation of}}
template<typename T> void in_instantiation_x1() {
typename T::X1 x1; // expected-warning{{qualified reference to 'X1' is a constructor name rather than a type in this context}}
typename T::template X1<int> x1i; // expected-warning{{qualified reference to 'X1' is a constructor name rather than a template name in this context}}
typename T::X0 x0;
}
template void in_instantiation_x1<X1<int> >(); // expected-note {{instantiation of}}
namespace sfinae {
template<typename T> void f(typename T::X0 *) = delete; // expected-warning 0-1{{extension}}
template<typename T> void f(...);
void g() { f<X0>(0); }
}
namespace versus_injected_class_name {
template <typename T> struct A : T::B {
struct T::B *p;
typename T::B::type a;
A() : T::B() {}
typename T::B b; // expected-warning {{qualified reference to 'B' is a constructor name rather than a type in this context}}
};
struct B {
typedef int type;
};
template struct A<B>; // expected-note {{in instantiation of}}
}
// We have a special case for lookup within using-declarations that are
// member-declarations: foo::bar::baz::baz always names baz's constructor
// in such a context, even if looking up 'baz' within foo::bar::baz would
// not find the injected-class-name. Likewise foo::bar::baz<T>::baz also
// names the constructor.
namespace InhCtor {
struct A {
A(int);
protected:
int T();
};
typedef A T;
struct B : A {
// This is a using-declaration for 'int A::T()' in C++98, but is an
// inheriting constructor declaration in C++11.
using InhCtor::T::T;
};
#if __cplusplus < 201103L
B b(123); // expected-error {{no matching constructor}}
// expected-note@-7 2{{candidate constructor}}
int n = b.T(); // ok, accessible
#else
B b(123); // ok, inheriting constructor
int n = b.T(); // expected-error {{'T' is a protected member of 'InhCtor::A'}}
// expected-note@-15 {{declared protected here}}
// FIXME: EDG and GCC reject this too, but it's not clear why it would be
// ill-formed.
template<typename T>
struct S : T {
struct U : S { // expected-note 6{{candidate}}
using S::S;
};
using T::T;
};
S<A>::U ua(0); // expected-error {{no match}}
S<B>::U ub(0); // expected-error {{no match}}
template<typename T>
struct X : T {
using T::Z::U::U;
};
template<typename T>
struct X2 : T {
using T::Z::template V<int>::V;
};
struct Y {
struct Z {
typedef Y U;
template<typename T> using V = Y;
};
Y(int);
};
X<Y> xy(0);
namespace Repeat {
struct A {
struct T {
T(int);
};
};
struct Z : A {
using A::A::A;
};
template<typename T>
struct ZT : T::T {
using T::T::T;
};
}
namespace NS {
struct NS {};
}
struct DerivedFromNS : NS::NS {
// No special case unless the NNS names a class.
using InhCtor::NS::NS; // expected-error {{using declaration in class refers into 'InhCtor::NS::', which is not a class}}
};
// FIXME: Consider reusing the same diagnostic between dependent and non-dependent contexts
typedef int I;
struct UsingInt {
using I::I; // expected-error {{'InhCtor::I' (aka 'int') is not a class, namespace, or enumeration}}
};
template<typename T> struct UsingIntTemplate {
using T::T; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
};
UsingIntTemplate<int> uit; // expected-note {{here}}
// This case is odd: we don't name the constructor of a dependent base as
// Base::Base, but we still happen to have enough information to identify
// when parsing the template that we're inheriting constructors.
//
// FIXME: Once CWG 2070 is resolved, check whether this case should be
// accepted or not.
namespace DependentCtorName {
template <typename T> struct B { B(int); };
template <typename T> struct A : B<T> {
using X = B<T>;
using X::B;
};
A<int> ab = 0;
}
#endif
}