]> granicus.if.org Git - clang/commitdiff
Improve diagnostics for missing members. This renames the err_typecheck_no_member...
authorAnders Carlsson <andersca@mac.com>
Sun, 30 Aug 2009 00:54:35 +0000 (00:54 +0000)
committerAnders Carlsson <andersca@mac.com>
Sun, 30 Aug 2009 00:54:35 +0000 (00:54 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80469 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.cpp
lib/Sema/Sema.h
lib/Sema/SemaCXXScopeSpec.cpp
lib/Sema/SemaDecl.cpp
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaExpr.cpp
test/SemaCXX/missing-members.cpp [new file with mode: 0644]

index b2c54036869f73d18867982f867db04807441a5b..98e91b6ac5f844a7caeefd56377543fa88dedb56 100644 (file)
@@ -1296,7 +1296,14 @@ def note_member_reference_needs_call : Note<
   "perhaps you meant to call this function with '()'?">;
 
 def err_typecheck_incomplete_tag : Error<"incomplete definition of type %0">;
-def err_typecheck_no_member : Error<"no member named %0">;
+def err_typecheck_no_member_deprecated : Error<"no member named %0">;
+def err_typecheck_record_no_member : Error<
+  "%select{struct|union|class}0 %q1 has no member named %2">;
+def err_typecheck_namespace_no_member : Error<
+  "namespace %q0 has no member named %1">;
+def err_typecheck_global_scope_no_member : Error<
+  "the global scope has no member named %0">;
+
 def err_member_redeclared : Error<"class member cannot be redeclared">;
 def err_member_def_does_not_match : Error<
   "out-of-line definition does not match any declaration in %0">;
index 0d9ad12edab059d36909c95291df03c7a903e8ae..f291be1abbad67ecd0f9db4a1c7e900ddab48763 100644 (file)
@@ -345,6 +345,31 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() {
   return 0;
 }
 
+void Sema::DiagnoseMissingMember(SourceLocation MemberLoc, 
+                                 DeclarationName Member,
+                                 NestedNameSpecifier *NNS, SourceRange Range) {
+  switch (NNS->getKind()) {
+  default: assert(0 && "Unexpected nested name specifier kind!");
+  case NestedNameSpecifier::TypeSpec: {
+    const Type *Ty = Context.getCanonicalType(NNS->getAsType());
+    RecordDecl *RD = cast<RecordType>(Ty)->getDecl();
+    Diag(MemberLoc, diag::err_typecheck_record_no_member)
+      << RD->getTagKind() << RD << Member << Range;
+    break;
+  }
+  case NestedNameSpecifier::Namespace: {
+    Diag(MemberLoc, diag::err_typecheck_namespace_no_member)
+      << NNS->getAsNamespace() << Member << Range;
+    break;
+  }
+  case NestedNameSpecifier::Global: {
+    Diag(MemberLoc, diag::err_typecheck_global_scope_no_member)
+      << Member << Range;
+    break;
+  }
+  }
+}
+
 Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
   if (!this->Emit())
     return;
index f3d202c2ffb6e1b7a16436dcd2a6c15677970f3e..0e45fe7f15993fe092a47ef2d458997434973034 100644 (file)
@@ -3461,6 +3461,9 @@ public:
                       QualType FieldTy, const Expr *BitWidth, 
                       bool *ZeroWidth = 0);
 
+  void DiagnoseMissingMember(SourceLocation MemberLoc, DeclarationName Member,
+                             NestedNameSpecifier *NNS, SourceRange Range);
+  
   //===--------------------------------------------------------------------===//
   // Extra semantic analysis beyond the C type system
 private:
index 2d89cfa07266a3b18abecf317cd75bb18d503c72..3172c0aa52ca97957f56faa0f7ff9c4d30b28ef6 100644 (file)
@@ -311,7 +311,7 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
   if (SD)
     DiagID = diag::err_expected_class_or_namespace;
   else if (SS.isSet())
-    DiagID = diag::err_typecheck_no_member;
+    DiagID = diag::err_typecheck_no_member_deprecated;
   else
     DiagID = diag::err_undeclared_var_use;
 
index 3eece142e9b9ce50cbb69e07d05b1cff733f92d3..4d05144918bb5534e4b7740423da6ca1b5da24d8 100644 (file)
@@ -2205,8 +2205,10 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
     }
   } else if (D.getCXXScopeSpec().isSet()) {
     // No previous declaration in the qualifying scope.
-    Diag(D.getIdentifierLoc(), diag::err_typecheck_no_member)
-      << Name << D.getCXXScopeSpec().getRange();
+    NestedNameSpecifier *NNS = 
+      (NestedNameSpecifier *)D.getCXXScopeSpec().getScopeRep();
+    DiagnoseMissingMember(D.getIdentifierLoc(), Name, NNS, 
+                          D.getCXXScopeSpec().getRange());
     NewVD->setInvalidDecl();
   }
 
index 6d32f3fdbf63ba1e225f86cf9d6606217d025d09..1aac43c1692fc0fe095bdca1a795ba9cf703a9dd 100644 (file)
@@ -2189,7 +2189,7 @@ NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc,
                                        Name, LookupOrdinaryName);
   
   if (!R) {
-    Diag(IdentLoc, diag::err_typecheck_no_member) << Name << SS.getRange();
+    Diag(IdentLoc, diag::err_typecheck_no_member_deprecated) << Name << SS.getRange();
     return 0;
   }
 
index cfb9eb658deee2294555df58d5566e927d13ec22..f304ac30945c8df48a1a02c88aac4ba85a118033 100644 (file)
@@ -789,10 +789,12 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
     else {
       // If this name wasn't predeclared and if this is not a function call,
       // diagnose the problem.
-      if (SS && !SS->isEmpty())
-        return ExprError(Diag(Loc, diag::err_typecheck_no_member)
-          << Name << SS->getRange());
-      else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
+      if (SS && !SS->isEmpty()) {
+        DiagnoseMissingMember(Loc, Name, 
+                              (NestedNameSpecifier *)SS->getScopeRep(),
+                              SS->getRange());
+        return ExprError();
+      } else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
                Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
         return ExprError(Diag(Loc, diag::err_undeclared_use)
           << Name.getAsString());
@@ -2088,7 +2090,7 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
     }
 
     if (!Result)
-      return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member)
+      return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member_deprecated)
                << MemberName << BaseExpr->getSourceRange());
     if (Result.isAmbiguous()) {
       DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc,
@@ -5475,7 +5477,7 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
                                         .getAsDecl());
       // FIXME: Leaks Res
       if (!MemberDecl)
-        return ExprError(Diag(BuiltinLoc, diag::err_typecheck_no_member)
+        return ExprError(Diag(BuiltinLoc, diag::err_typecheck_no_member_deprecated)
          << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd));
 
       // FIXME: C++: Verify that MemberDecl isn't a static field.
diff --git a/test/SemaCXX/missing-members.cpp b/test/SemaCXX/missing-members.cpp
new file mode 100644 (file)
index 0000000..a737226
--- /dev/null
@@ -0,0 +1,20 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+namespace A {
+  namespace B {
+    class C { };
+    struct S { };
+    union U { };
+  }
+}
+
+void f() {
+  A::B::i; // expected-error {{namespace 'A::B' has no member named 'i'}}
+  A::B::C::i; // expected-error {{class 'A::B::C' has no member named 'i'}}
+  ::i; // expected-error {{the global scope has no member named 'i'}}
+}
+
+int A::B::i = 10; // expected-error {{namespace 'A::B' has no member named 'i'}}
+int A::B::C::i = 10; // expected-error {{class 'A::B::C' has no member named 'i'}}
+int A::B::S::i = 10; // expected-error {{struct 'A::B::S' has no member named 'i'}}
+int A::B::U::i = 10; // expected-error {{union 'A::B::U' has no member named 'i'}}
+