From: Anders Carlsson Date: Sun, 30 Aug 2009 00:54:35 +0000 (+0000) Subject: Improve diagnostics for missing members. This renames the err_typecheck_no_member... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f4d84b663ef7dda959cbe45561d90e59760cbb74;p=clang Improve diagnostics for missing members. This renames the err_typecheck_no_member to err_typecheck_no_member_deprecated. The idea is that err_typecheck_no_member_deprecated should be phased out and any call sites that reference it should call DiagnoseMissingMember instead. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@80469 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b2c5403686..98e91b6ac5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 0d9ad12eda..f291be1abb 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -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(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; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index f3d202c2ff..0e45fe7f15 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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: diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 2d89cfa072..3172c0aa52 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -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; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 3eece142e9..4d05144918 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 6d32f3fdbf..1aac43c169 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index cfb9eb658d..f304ac3094 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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 index 0000000000..a7372266c3 --- /dev/null +++ b/test/SemaCXX/missing-members.cpp @@ -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'}} +