David Blaikie 6cab596218 Improve diagnostic for using non-class/namespace/scoped enum in a nested name specifier.
Rather than simply saying "X is not a class or namespace", clarify what
X is by providing the aka type in the case where X is a type, or
pointing to the named declaration if there's an unambiguous one to refer
to. In the ambiguous case, the ambiguities are already enumerated
(though could be clarified by describing what kind of entities they are)

Included a few FIXMEs in tests where some further improvements could be
made.

llvm-svn: 201038
2014-02-09 06:54:23 +00:00

119 lines
3.6 KiB
C++

// RUN: %clang_cc1 -fsyntax-only -verify -std=c++98 %s
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
struct X0 {
X0 f1();
X0 f2();
};
template<typename T>
struct X1 {
X1<T>(int);
(X1<T>)(float);
X1 f2();
X1 f2(int);
X1 f2(float);
};
// 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 wherever a constructor can be declared}}
struct X0::X0 X0::f2() { return X0(); }
template<typename T> X1<T>::X1<T> X1<T>::f2() { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name wherever a constructor can be declared}}
template<typename T> X1<T>::X1<T> (X1<T>::f2)(int) { } // expected-error{{qualified reference to 'X1' is a constructor name rather than a template name wherever a constructor can be declared}}
template<typename T> struct X1<T>::X1<T> (X1<T>::f2)(float) { }
// 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}}
template<typename T>
struct S : T {
struct U : S {
using S::S;
};
using T::T;
};
S<A>::U ua(0);
S<B>::U ub(0);
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 {{'I' (aka 'int') is not a class, namespace, or scoped 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}}
#endif
}