summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Parse/ParseDecl.cpp35
-rw-r--r--clang/lib/Sema/Sema.cpp1
-rw-r--r--clang/lib/Sema/Sema.h7
-rw-r--r--clang/lib/Sema/SemaDecl.cpp31
4 files changed, 67 insertions, 7 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index e15a4cd6880..b56c33170cb 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -688,13 +688,36 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
}
}
- // Since this is almost certainly an invalid type name, emit a
- // diagnostic that says it, eat the token, and mark the declspec as
- // invalid.
- SourceRange R;
- if (SS) R = SS->getRange();
+ // This is almost certainly an invalid type name. Let the action emit a
+ // diagnostic and attempt to recover.
+ Action::TypeTy *T = 0;
+ if (Actions.DiagnoseUnknownTypeName(*Tok.getIdentifierInfo(), Loc,
+ CurScope, SS, T)) {
+ // The action emitted a diagnostic, so we don't have to.
+ if (T) {
+ // The action has suggested that the type T could be used. Set that as
+ // the type in the declaration specifiers, consume the would-be type
+ // name token, and we're done.
+ const char *PrevSpec;
+ unsigned DiagID;
+ DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec, DiagID, T,
+ false);
+ DS.SetRangeEnd(Tok.getLocation());
+ ConsumeToken();
+
+ // There may be other declaration specifiers after this.
+ return true;
+ }
+
+ // Fall through; the action had no suggestion for us.
+ } else {
+ // The action did not emit a diagnostic, so emit one now.
+ SourceRange R;
+ if (SS) R = SS->getRange();
+ Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R;
+ }
- Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R;
+ // Mark this as an error.
const char *PrevSpec;
unsigned DiagID;
DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec, DiagID);
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index c289abfea86..ba05a07f265 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -117,6 +117,7 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
llvm::raw_string_ostream OS(S);
reinterpret_cast<NestedNameSpecifier*> (Val)->print(OS,
Context.PrintingPolicy);
+ NeedQuotes = false;
} else {
assert(Kind == Diagnostic::ak_declcontext);
DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h
index 465eca70ed3..04addfd3a98 100644
--- a/clang/lib/Sema/Sema.h
+++ b/clang/lib/Sema/Sema.h
@@ -523,7 +523,12 @@ public:
Scope *S, const CXXScopeSpec *SS,
bool isClassName = false);
virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S);
-
+ virtual bool DiagnoseUnknownTypeName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TypeTy *&SuggestedType);
+
virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) {
return HandleDeclarator(S, D, MultiTemplateParamsArg(*this), false);
}
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 9f03cb284ca..606b33f5f74 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -23,6 +23,7 @@
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/Parse/DeclSpec.h"
+#include "clang/Parse/ParseDiagnostic.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TargetInfo.h"
@@ -199,6 +200,36 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) {
return DeclSpec::TST_unspecified;
}
+bool Sema::DiagnoseUnknownTypeName(const IdentifierInfo &II,
+ SourceLocation IILoc,
+ Scope *S,
+ const CXXScopeSpec *SS,
+ TypeTy *&SuggestedType) {
+ // We don't have anything to suggest (yet).
+ SuggestedType = 0;
+
+ // FIXME: Should we move the logic that tries to recover from a missing tag
+ // (struct, union, enum) from Parser::ParseImplicitInt here, instead?
+
+ if (!SS)
+ Diag(IILoc, diag::err_unknown_typename) << &II;
+ else if (DeclContext *DC = computeDeclContext(*SS, false))
+ Diag(IILoc, diag::err_typename_nested_not_found)
+ << &II << DC << SS->getRange();
+ else if (isDependentScopeSpecifier(*SS)) {
+ Diag(SS->getRange().getBegin(), diag::err_typename_missing)
+ << (NestedNameSpecifier *)SS->getScopeRep() << II.getName()
+ << SourceRange(SS->getRange().getBegin(), IILoc)
+ << CodeModificationHint::CreateInsertion(SS->getRange().getBegin(),
+ "typename ");
+ SuggestedType = ActOnTypenameType(SourceLocation(), *SS, II, IILoc).get();
+ } else {
+ assert(SS && SS->isInvalid() &&
+ "Invalid scope specifier has already been diagnosed");
+ }
+
+ return true;
+}
// Determines the context to return to after temporarily entering a
// context. This depends in an unnecessarily complicated way on the
OpenPOWER on IntegriCloud