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
This commit is contained in:
David Blaikie 2014-02-09 06:54:23 +00:00
parent 158ba130ee
commit 6cab596218
8 changed files with 37 additions and 29 deletions

View File

@ -5253,9 +5253,10 @@ def err_typecheck_deleted_function : Error<
"conversion function %diff{from $ to $|between types}0,1 " "conversion function %diff{from $ to $|between types}0,1 "
"invokes a deleted function">; "invokes a deleted function">;
def err_expected_class_or_namespace : Error<"expected a class or namespace">; def err_expected_class_or_namespace : Error<"%0 is not a class"
def err_expected_class : Error<"%0 is not a class%select{ or namespace|, " "%select{ or namespace|, namespace, or scoped enumeration}1">;
"namespace, or scoped enumeration}1">; def note_expected_class_or_namespace_declared_here : Note<
"%0 declared here">;
def err_invalid_declarator_scope : Error<"cannot define or redeclare %0 here " def err_invalid_declarator_scope : Error<"cannot define or redeclare %0 here "
"because namespace %1 does not enclose namespace %2">; "because namespace %1 does not enclose namespace %2">;
def err_invalid_declarator_global_scope : Error< def err_invalid_declarator_global_scope : Error<

View File

@ -654,20 +654,23 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
} }
} }
unsigned DiagID; if (!Found.empty()) {
if (!Found.empty()) if (TypeDecl *TD = Found.getAsSingle<TypeDecl>())
DiagID = diag::err_expected_class_or_namespace; Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
else if (SS.isSet()) { << QualType(TD->getTypeForDecl(), 0) << getLangOpts().CPlusPlus;
Diag(IdentifierLoc, diag::err_no_member) else {
<< &Identifier << LookupCtx << SS.getRange(); Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
return true; << &Identifier << getLangOpts().CPlusPlus;
} else if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
DiagID = diag::err_undeclared_var_use; Diag(ND->getLocation(),
diag::note_expected_class_or_namespace_declared_here)
if (SS.isSet()) << &Identifier;
Diag(IdentifierLoc, DiagID) << &Identifier << SS.getRange(); }
} else if (SS.isSet())
Diag(IdentifierLoc, diag::err_no_member) << &Identifier << LookupCtx
<< SS.getRange();
else else
Diag(IdentifierLoc, DiagID) << &Identifier; Diag(IdentifierLoc, diag::err_undeclared_var_use) << &Identifier;
return true; return true;
} }
@ -698,7 +701,7 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
if (!T->isDependentType() && !T->getAs<TagType>()) { if (!T->isDependentType() && !T->getAs<TagType>()) {
Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class) Diag(DS.getTypeSpecTypeLoc(), diag::err_expected_class_or_namespace)
<< T << getLangOpts().CPlusPlus; << T << getLangOpts().CPlusPlus;
return true; return true;
} }

View File

@ -105,9 +105,10 @@ namespace InhCtor {
}; };
// FIXME: Consider reusing the same diagnostic between dependent and non-dependent contexts
typedef int I; typedef int I;
struct UsingInt { struct UsingInt {
using I::I; // expected-error {{expected a class or namespace}} using I::I; // expected-error {{'I' (aka 'int') is not a class, namespace, or scoped enumeration}}
}; };
template<typename T> struct UsingIntTemplate { template<typename T> struct UsingIntTemplate {
using T::T; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}} using T::T; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}

View File

@ -15,7 +15,7 @@ template <class T> struct Derived: Base<int>, Base<char> {
t->Base<T>::f(); t->Base<T>::f();
t->Base::f(); // expected-error{{member 'Base' found in multiple base classes of different types}} \ t->Base::f(); // expected-error{{member 'Base' found in multiple base classes of different types}} \
// expected-error{{no member named 'f' in 'X0'}} \ // expected-error{{no member named 'f' in 'X0'}} \
// expected-error{{expected a class or namespace}} // expected-error{{'Base' is not a class, namespace, or scoped enumeration}}
} }
}; };

View File

@ -94,7 +94,7 @@ struct Current : Derived {
Derived::Base1(), // expected-error {{type 'Derived::Base1' is not a direct or virtual base of 'Current'}} Derived::Base1(), // expected-error {{type 'Derived::Base1' is not a direct or virtual base of 'Current'}}
Derived::V(), Derived::V(),
::NonExisting(), // expected-error {{member initializer 'NonExisting' does not name a non-static data member or}} ::NonExisting(), // expected-error {{member initializer 'NonExisting' does not name a non-static data member or}}
INT::NonExisting() {} // expected-error {{expected a class or namespace}} \ INT::NonExisting() {} // expected-error {{'INT' (aka 'int') is not a class, namespace, or scoped enumeration}} \
// expected-error {{member initializer 'NonExisting' does not name a non-static data member or}} // expected-error {{member initializer 'NonExisting' does not name a non-static data member or}}
}; };

View File

@ -13,7 +13,7 @@ int A::*pdi1;
int (::A::*pdi2); int (::A::*pdi2);
int (A::*pfi)(int); int (A::*pfi)(int);
int B::*pbi; // expected-error {{expected a class or namespace}} int B::*pbi; // expected-error {{'B' is not a class, namespace, or scoped enumeration}}
int C::*pci; // expected-error {{'pci' does not point into a class}} int C::*pci; // expected-error {{'pci' does not point into a class}}
void A::*pdv; // expected-error {{'pdv' declared as a member pointer to void}} void A::*pdv; // expected-error {{'pdv' declared as a member pointer to void}}
int& A::*pdr; // expected-error {{'pdr' declared as a member pointer to a reference}} int& A::*pdr; // expected-error {{'pdr' declared as a member pointer to a reference}}

View File

@ -85,10 +85,13 @@ struct A2::CC::NC {
void f3() { void f3() {
N::x = 0; // expected-error {{use of undeclared identifier 'N'}} N::x = 0; // expected-error {{use of undeclared identifier 'N'}}
int N; // FIXME: Consider including the kind of entity that 'N' is ("variable 'N'
N::x = 0; // expected-error {{expected a class or namespace}} // declared here", "template 'X' declared here", etc) to help explain what it
// is if it's 'not a class, namespace, or scoped enumeration'.
int N; // expected-note {{'N' declared here}}
N::x = 0; // expected-error {{'N' is not a class, namespace, or scoped enumeration}}
{ int A; A::ax = 0; } { int A; A::ax = 0; }
{ typedef int A; A::ax = 0; } // expected-error{{expected a class or namespace}} { typedef int A; A::ax = 0; } // expected-error{{'A' (aka 'int') is not a class, namespace, or scoped enumeration}}
{ typedef A::C A; A::ax = 0; } // expected-error {{no member named 'ax'}} { typedef A::C A; A::ax = 0; } // expected-error {{no member named 'ax'}}
{ typedef A::C A; A::cx = 0; } { typedef A::C A; A::cx = 0; }
} }
@ -114,7 +117,7 @@ namespace E {
}; };
void f() { void f() {
return E::X; // expected-error{{expected a class or namespace}} return E::X; // expected-error{{'E::Nested::E' is not a class, namespace, or scoped enumeration}}
} }
} }
} }
@ -308,4 +311,4 @@ namespace N {
} }
namespace TypedefNamespace { typedef int F; }; namespace TypedefNamespace { typedef int F; };
TypedefNamespace::F::NonexistentName BadNNSWithCXXScopeSpec; // expected-error {{expected a class or namespace}} TypedefNamespace::F::NonexistentName BadNNSWithCXXScopeSpec; // expected-error {{'F' (aka 'int') is not a class, namespace, or scoped enumeration}}

View File

@ -53,7 +53,7 @@ void g(B *b) {
// PR9759 // PR9759
class Forward; class Forward;
@interface D { @interface D { // expected-note 2 {{'D' declared here}}
@public @public
int ivar; int ivar;
} }
@ -64,6 +64,6 @@ class Forward;
void testD(D *d) { void testD(D *d) {
d.Forward::property = 17; // expected-error{{property access cannot be qualified with 'Forward::'}} d.Forward::property = 17; // expected-error{{property access cannot be qualified with 'Forward::'}}
d->Forward::ivar = 12; // expected-error{{instance variable access cannot be qualified with 'Forward::'}} d->Forward::ivar = 12; // expected-error{{instance variable access cannot be qualified with 'Forward::'}}
d.D::property = 17; // expected-error{{expected a class or namespace}} d.D::property = 17; // expected-error{{'D' is not a class, namespace, or scoped enumeration}}
d->D::ivar = 12; // expected-error{{expected a class or namespace}} d->D::ivar = 12; // expected-error{{'D' is not a class, namespace, or scoped enumeration}}
} }