summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Blaikie <dblaikie@gmail.com>2014-02-09 06:54:23 +0000
committerDavid Blaikie <dblaikie@gmail.com>2014-02-09 06:54:23 +0000
commit97e7a0350d369f8c8a55d1a3a1e10917363d0f1f (patch)
tree4055b28f67ba15390c575af42d4fd943a1592c5a
parentc809e1493facfee2a47e47d735c6db16a5c65ea4 (diff)
downloadclang-97e7a0350d369f8c8a55d1a3a1e10917363d0f1f.tar.gz
clang-97e7a0350d369f8c8a55d1a3a1e10917363d0f1f.tar.bz2
clang-97e7a0350d369f8c8a55d1a3a1e10917363d0f1f.tar.xz
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. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201038 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td7
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp31
-rw-r--r--test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp3
-rw-r--r--test/CXX/temp/temp.res/temp.local/p3.cpp2
-rw-r--r--test/SemaCXX/constructor-initializer.cpp2
-rw-r--r--test/SemaCXX/member-pointer.cpp2
-rw-r--r--test/SemaCXX/nested-name-spec.cpp13
-rw-r--r--test/SemaObjCXX/propert-dot-error.mm6
8 files changed, 37 insertions, 29 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 0e8e213dc9..edbf97e500 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5253,9 +5253,10 @@ def err_typecheck_deleted_function : Error<
"conversion function %diff{from $ to $|between types}0,1 "
"invokes a deleted function">;
-def err_expected_class_or_namespace : Error<"expected a class or namespace">;
-def err_expected_class : Error<"%0 is not a class%select{ or namespace|, "
- "namespace, or scoped enumeration}1">;
+def err_expected_class_or_namespace : Error<"%0 is not a class"
+ "%select{ or namespace|, 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 "
"because namespace %1 does not enclose namespace %2">;
def err_invalid_declarator_global_scope : Error<
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 9a390a7e26..ef1eaf2c14 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -654,20 +654,23 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
}
}
- unsigned DiagID;
- if (!Found.empty())
- DiagID = diag::err_expected_class_or_namespace;
- else if (SS.isSet()) {
- Diag(IdentifierLoc, diag::err_no_member)
- << &Identifier << LookupCtx << SS.getRange();
- return true;
- } else
- DiagID = diag::err_undeclared_var_use;
-
- if (SS.isSet())
- Diag(IdentifierLoc, DiagID) << &Identifier << SS.getRange();
+ if (!Found.empty()) {
+ if (TypeDecl *TD = Found.getAsSingle<TypeDecl>())
+ Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
+ << QualType(TD->getTypeForDecl(), 0) << getLangOpts().CPlusPlus;
+ else {
+ Diag(IdentifierLoc, diag::err_expected_class_or_namespace)
+ << &Identifier << getLangOpts().CPlusPlus;
+ if (NamedDecl *ND = Found.getAsSingle<NamedDecl>())
+ Diag(ND->getLocation(),
+ diag::note_expected_class_or_namespace_declared_here)
+ << &Identifier;
+ }
+ } else if (SS.isSet())
+ Diag(IdentifierLoc, diag::err_no_member) << &Identifier << LookupCtx
+ << SS.getRange();
else
- Diag(IdentifierLoc, DiagID) << &Identifier;
+ Diag(IdentifierLoc, diag::err_undeclared_var_use) << &Identifier;
return true;
}
@@ -698,7 +701,7 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS,
QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
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;
return true;
}
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
index 1f78a738f3..b9e83988cf 100644
--- a/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
+++ b/test/CXX/basic/basic.lookup/basic.lookup.qual/class.qual/p2.cpp
@@ -105,9 +105,10 @@ namespace InhCtor {
};
+ // FIXME: Consider reusing the same diagnostic between dependent and non-dependent contexts
typedef int I;
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 {
using T::T; // expected-error {{type 'int' cannot be used prior to '::' because it has no members}}
diff --git a/test/CXX/temp/temp.res/temp.local/p3.cpp b/test/CXX/temp/temp.res/temp.local/p3.cpp
index 54da8856fe..e29ced19bc 100644
--- a/test/CXX/temp/temp.res/temp.local/p3.cpp
+++ b/test/CXX/temp/temp.res/temp.local/p3.cpp
@@ -15,7 +15,7 @@ template <class T> struct Derived: Base<int>, Base<char> {
t->Base<T>::f();
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{{expected a class or namespace}}
+ // expected-error{{'Base' is not a class, namespace, or scoped enumeration}}
}
};
diff --git a/test/SemaCXX/constructor-initializer.cpp b/test/SemaCXX/constructor-initializer.cpp
index 697f718eab..81dc19ea6d 100644
--- a/test/SemaCXX/constructor-initializer.cpp
+++ b/test/SemaCXX/constructor-initializer.cpp
@@ -94,7 +94,7 @@ struct Current : Derived {
Derived::Base1(), // expected-error {{type 'Derived::Base1' is not a direct or virtual base of 'Current'}}
Derived::V(),
::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}}
};
diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp
index 82873d9c7d..b8631bcf3e 100644
--- a/test/SemaCXX/member-pointer.cpp
+++ b/test/SemaCXX/member-pointer.cpp
@@ -13,7 +13,7 @@ int A::*pdi1;
int (::A::*pdi2);
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}}
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}}
diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp
index a0bac059a2..8587e70158 100644
--- a/test/SemaCXX/nested-name-spec.cpp
+++ b/test/SemaCXX/nested-name-spec.cpp
@@ -85,10 +85,13 @@ struct A2::CC::NC {
void f3() {
N::x = 0; // expected-error {{use of undeclared identifier 'N'}}
- int N;
- N::x = 0; // expected-error {{expected a class or namespace}}
+ // FIXME: Consider including the kind of entity that 'N' is ("variable 'N'
+ // 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; }
- { 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::cx = 0; }
}
@@ -114,7 +117,7 @@ namespace E {
};
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; };
-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}}
diff --git a/test/SemaObjCXX/propert-dot-error.mm b/test/SemaObjCXX/propert-dot-error.mm
index 2a462e4ffa..e28204c665 100644
--- a/test/SemaObjCXX/propert-dot-error.mm
+++ b/test/SemaObjCXX/propert-dot-error.mm
@@ -53,7 +53,7 @@ void g(B *b) {
// PR9759
class Forward;
-@interface D {
+@interface D { // expected-note 2 {{'D' declared here}}
@public
int ivar;
}
@@ -64,6 +64,6 @@ class Forward;
void testD(D *d) {
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.D::property = 17; // expected-error{{expected a class or namespace}}
- d->D::ivar = 12; // 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{{'D' is not a class, namespace, or scoped enumeration}}
}