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.

llvm-svn: 80469
This commit is contained in:
Anders Carlsson 2009-08-30 00:54:35 +00:00
parent 744a249493
commit 896c230a19
8 changed files with 70 additions and 11 deletions

View 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">;

View 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;

View 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:

View 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;

View 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();
}

View 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;
}

View 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.

View File

@ -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'}}