aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-10-13 21:16:44 +0000
committerDouglas Gregor <dgregor@apple.com>2009-10-13 21:16:44 +0000
commit3f09327b26033d0a9676d52d80cf92c48f581aff (patch)
tree039a1889fa3bd411d947c5642da2182868e05489 /lib/Sema
parentcee1b54e11cb4d460634e6ecedbe75c7c2382389 (diff)
Unify our diagnostic printing for errors of the form, "we didn't like
what we found when we looked into <blah>", where <blah> is a DeclContext*. We can now format DeclContext*'s in nice ways, e.g., "namespace N", "the global namespace", "'class Foo'". This is part of PR3990, but we're not quite there yet. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84028 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r--lib/Sema/Sema.cpp157
-rw-r--r--lib/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaCXXScopeSpec.cpp4
-rw-r--r--lib/Sema/SemaDecl.cpp9
-rw-r--r--lib/Sema/SemaDeclCXX.cpp3
-rw-r--r--lib/Sema/SemaExpr.cpp19
-rw-r--r--lib/Sema/SemaTemplate.cpp10
7 files changed, 107 insertions, 98 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 3aae2563d1..c289abfea8 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -23,6 +23,54 @@
#include "clang/Basic/TargetInfo.h"
using namespace clang;
+/// \brief Convert the given type to a string suitable for printing as part of
+/// a diagnostic.
+///
+/// \param Context the context in which the type was allocated
+/// \param Ty the type to print
+static std::string ConvertTypeToDiagnosticString(ASTContext &Context,
+ QualType Ty) {
+ // FIXME: Playing with std::string is really slow.
+ std::string S = Ty.getAsString(Context.PrintingPolicy);
+
+ // If this is a sugared type (like a typedef, typeof, etc), then unwrap one
+ // level of the sugar so that the type is more obvious to the user.
+ QualType DesugaredTy = Ty.getDesugaredType();
+
+ if (Ty != DesugaredTy &&
+ // If the desugared type is a vector type, we don't want to expand it,
+ // it will turn into an attribute mess. People want their "vec4".
+ !isa<VectorType>(DesugaredTy) &&
+
+ // Don't aka just because we saw an elaborated type...
+ (!isa<ElaboratedType>(Ty) ||
+ cast<ElaboratedType>(Ty)->desugar() != DesugaredTy) &&
+
+ // ...or a qualified name type...
+ (!isa<QualifiedNameType>(Ty) ||
+ cast<QualifiedNameType>(Ty)->desugar() != DesugaredTy) &&
+
+ // ...or a non-dependent template specialization.
+ (!isa<TemplateSpecializationType>(Ty) || Ty->isDependentType()) &&
+
+ // Don't desugar magic Objective-C types.
+ Ty.getUnqualifiedType() != Context.getObjCIdType() &&
+ Ty.getUnqualifiedType() != Context.getObjCClassType() &&
+ Ty.getUnqualifiedType() != Context.getObjCSelType() &&
+ Ty.getUnqualifiedType() != Context.getObjCProtoType() &&
+
+ // Not va_list.
+ Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) {
+ S = "'"+S+"' (aka '";
+ S += DesugaredTy.getAsString(Context.PrintingPolicy);
+ S += "')";
+ return S;
+ }
+
+ S = "'" + S + "'";
+ return S;
+}
+
/// ConvertQualTypeToStringFn - This function is used to pretty print the
/// specified QualType as a string in diagnostics.
static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
@@ -33,50 +81,14 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
std::string S;
+ bool NeedQuotes = true;
if (Kind == Diagnostic::ak_qualtype) {
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for QualType argument");
QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
-
- // FIXME: Playing with std::string is really slow.
- S = Ty.getAsString(Context.PrintingPolicy);
-
- // If this is a sugared type (like a typedef, typeof, etc), then unwrap one
- // level of the sugar so that the type is more obvious to the user.
- QualType DesugaredTy = Ty.getDesugaredType();
-
- if (Ty != DesugaredTy &&
- // If the desugared type is a vector type, we don't want to expand it,
- // it will turn into an attribute mess. People want their "vec4".
- !isa<VectorType>(DesugaredTy) &&
-
- // Don't aka just because we saw an elaborated type...
- (!isa<ElaboratedType>(Ty) ||
- cast<ElaboratedType>(Ty)->desugar() != DesugaredTy) &&
-
- // ...or a qualified name type...
- (!isa<QualifiedNameType>(Ty) ||
- cast<QualifiedNameType>(Ty)->desugar() != DesugaredTy) &&
-
- // ...or a non-dependent template specialization.
- (!isa<TemplateSpecializationType>(Ty) || Ty->isDependentType()) &&
-
- // Don't desugar magic Objective-C types.
- Ty.getUnqualifiedType() != Context.getObjCIdType() &&
- Ty.getUnqualifiedType() != Context.getObjCClassType() &&
- Ty.getUnqualifiedType() != Context.getObjCSelType() &&
- Ty.getUnqualifiedType() != Context.getObjCProtoType() &&
-
- // Not va_list.
- Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) {
- S = "'"+S+"' (aka '";
- S += DesugaredTy.getAsString(Context.PrintingPolicy);
- S += "')";
- Output.append(S.begin(), S.end());
- return;
- }
-
+ S = ConvertTypeToDiagnosticString(Context, Ty);
+ NeedQuotes = false;
} else if (Kind == Diagnostic::ak_declarationname) {
DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
@@ -101,16 +113,50 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
reinterpret_cast<NamedDecl*>(Val)->getNameForDiagnostic(S,
Context.PrintingPolicy,
Qualified);
- } else {
+ } else if (Kind == Diagnostic::ak_nestednamespec) {
llvm::raw_string_ostream OS(S);
- assert(Kind == Diagnostic::ak_nestednamespec);
reinterpret_cast<NestedNameSpecifier*> (Val)->print(OS,
Context.PrintingPolicy);
+ } else {
+ assert(Kind == Diagnostic::ak_declcontext);
+ DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
+ NeedQuotes = false;
+ if (!DC) {
+ assert(false && "Should never have a null declaration context");
+ S = "unknown context";
+ } else if (DC->isTranslationUnit()) {
+ // FIXME: Get these strings from some localized place
+ if (Context.getLangOptions().CPlusPlus)
+ S = "the global namespace";
+ else
+ S = "the global scope";
+ } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
+ S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type));
+ NeedQuotes = false;
+ } else {
+ // FIXME: Get these strings from some localized place
+ NamedDecl *ND = cast<NamedDecl>(DC);
+ if (isa<NamespaceDecl>(ND))
+ S += "namespace ";
+ else if (isa<ObjCMethodDecl>(ND))
+ S += "method ";
+ else if (isa<FunctionDecl>(ND))
+ S += "function ";
+
+ S += "'";
+ ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
+ S += "'";
+ NeedQuotes = false;
+ }
}
- Output.push_back('\'');
+ if (NeedQuotes)
+ Output.push_back('\'');
+
Output.append(S.begin(), S.end());
- Output.push_back('\'');
+
+ if (NeedQuotes)
+ Output.push_back('\'');
}
@@ -363,31 +409,6 @@ 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)
- << Member << RD->getTagKind() << RD << Range;
- break;
- }
- case NestedNameSpecifier::Namespace: {
- Diag(MemberLoc, diag::err_typecheck_namespace_no_member)
- << Member << NNS->getAsNamespace() << Range;
- break;
- }
- case NestedNameSpecifier::Global: {
- Diag(MemberLoc, diag::err_typecheck_global_namespace_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 fed2fbc081..465eca70ed 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -3720,9 +3720,6 @@ public:
QualType FieldTy, const Expr *BitWidth,
bool *ZeroWidth = 0);
- void DiagnoseMissingMember(SourceLocation MemberLoc, DeclarationName Member,
- NestedNameSpecifier *NNS, SourceRange Range);
-
/// adjustFunctionParamType - Converts the type of a function parameter to a
// type that can be passed as an argument type to
/// ASTContext::getFunctionType.
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 911cf67770..10c138c755 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -471,9 +471,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S,
if (SD)
DiagID = diag::err_expected_class_or_namespace;
else if (SS.isSet()) {
- DiagnoseMissingMember(IdLoc, DeclarationName(&II),
- (NestedNameSpecifier *)SS.getScopeRep(),
- SS.getRange());
+ Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange();
return 0;
} else
DiagID = diag::err_undeclared_var_use;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index a1582a900f..9f03cb284c 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -2229,10 +2229,9 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC,
}
} else if (D.getCXXScopeSpec().isSet()) {
// No previous declaration in the qualifying scope.
- NestedNameSpecifier *NNS =
- (NestedNameSpecifier *)D.getCXXScopeSpec().getScopeRep();
- DiagnoseMissingMember(D.getIdentifierLoc(), Name, NNS,
- D.getCXXScopeSpec().getRange());
+ Diag(D.getIdentifierLoc(), diag::err_no_member)
+ << Name << computeDeclContext(D.getCXXScopeSpec(), true)
+ << D.getCXXScopeSpec().getRange();
NewVD->setInvalidDecl();
}
@@ -2844,7 +2843,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
// matches (e.g., those that differ only in cv-qualifiers and
// whether the parameter types are references).
Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match)
- << cast<NamedDecl>(DC) << D.getCXXScopeSpec().getRange();
+ << Name << DC << D.getCXXScopeSpec().getRange();
NewFD->setInvalidDecl();
LookupResult Prev;
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 646ac75dd3..82cdd2f57a 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2767,7 +2767,8 @@ NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc,
LookupQualifiedName(R, LookupContext, Name, LookupOrdinaryName);
if (R.empty()) {
- DiagnoseMissingMember(IdentLoc, Name, NNS, SS.getRange());
+ Diag(IdentLoc, diag::err_no_member)
+ << Name << LookupContext << SS.getRange();
return 0;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index b7c2308541..194317ce23 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -802,12 +802,11 @@ 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()) {
- DiagnoseMissingMember(Loc, Name,
- (NestedNameSpecifier *)SS->getScopeRep(),
- SS->getRange());
- return ExprError();
- } else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
+ if (SS && !SS->isEmpty())
+ return ExprError(Diag(Loc, diag::err_no_member)
+ << Name << computeDeclContext(*SS, false)
+ << SS->getRange());
+ else if (Name.getNameKind() == DeclarationName::CXXOperatorName ||
Name.getNameKind() == DeclarationName::CXXConversionFunctionName)
return ExprError(Diag(Loc, diag::err_undeclared_use)
<< Name.getAsString());
@@ -2185,8 +2184,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc,
LookupQualifiedName(Result, DC, MemberName, LookupMemberName, false);
if (Result.empty())
- return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member_deprecated)
- << MemberName << BaseExpr->getSourceRange());
+ return ExprError(Diag(MemberLoc, diag::err_no_member)
+ << MemberName << DC << BaseExpr->getSourceRange());
if (Result.isAmbiguous()) {
DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc,
BaseExpr->getSourceRange());
@@ -5689,8 +5688,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S,
= dyn_cast_or_null<FieldDecl>(R.getAsSingleDecl(Context));
// FIXME: Leaks Res
if (!MemberDecl)
- return ExprError(Diag(BuiltinLoc, diag::err_typecheck_no_member_deprecated)
- << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd));
+ return ExprError(Diag(BuiltinLoc, diag::err_no_member)
+ << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd));
// FIXME: C++: Verify that MemberDecl isn't a static field.
// FIXME: Verify that MemberDecl isn't a bitfield.
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 3ee15a5b4d..4a410ecb14 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -3903,10 +3903,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
Decl *Referenced = 0;
switch (Result.getKind()) {
case LookupResult::NotFound:
- if (Ctx->isTranslationUnit())
- DiagID = diag::err_typename_nested_not_found_global;
- else
- DiagID = diag::err_typename_nested_not_found;
+ DiagID = diag::err_typename_nested_not_found;
break;
case LookupResult::Found:
@@ -3933,10 +3930,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
// If we get here, it's because name lookup did not find a
// type. Emit an appropriate diagnostic and return an error.
- if (NamedDecl *NamedCtx = dyn_cast<NamedDecl>(Ctx))
- Diag(Range.getEnd(), DiagID) << Range << Name << NamedCtx;
- else
- Diag(Range.getEnd(), DiagID) << Range << Name;
+ Diag(Range.getEnd(), DiagID) << Range << Name << Ctx;
if (Referenced)
Diag(Referenced->getLocation(), diag::note_typename_refers_here)
<< Name;