summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2013-10-15 00:00:26 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2013-10-15 00:00:26 +0000
commitfb8b7b9a1c524c420728d1814997d6e988f992de (patch)
tree020250997da147b7c85dad004ee0f34e06bfa89b /clang/lib
parentb0cba4ce7570727d30510946b38588265a14efb1 (diff)
downloadbcm5719-llvm-fb8b7b9a1c524c420728d1814997d6e988f992de.tar.gz
bcm5719-llvm-fb8b7b9a1c524c420728d1814997d6e988f992de.zip
PR17567: Improve diagnostic for a mistyped constructor name. If we see something
that looks like a function declaration, except that it's missing a return type, try typo-correcting it to the relevant constructor name. In passing, fix a bug where the missing-type-specifier recovery codepath would drop a preceding scope specifier on the floor, leading to follow-on diagnostics and incorrect recovery for the auto-in-c++98 hack. llvm-svn: 192644
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Parse/ParseDecl.cpp47
-rw-r--r--clang/lib/Sema/SemaDeclCXX.cpp26
2 files changed, 58 insertions, 15 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 31349ce9946..0f480c13353 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2095,6 +2095,8 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
DS.getStorageClassSpec() == DeclSpec::SCS_auto) {
// Don't require a type specifier if we have the 'auto' storage class
// specifier in C++98 -- we'll promote it to a type specifier.
+ if (SS)
+ AnnotateScopeToken(*SS, /*IsNewAnnotation*/false);
return false;
}
@@ -2156,16 +2158,6 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
// Look ahead to the next token to try to figure out what this declaration
// was supposed to be.
switch (NextToken().getKind()) {
- case tok::comma:
- case tok::equal:
- case tok::kw_asm:
- case tok::l_brace:
- case tok::l_square:
- case tok::semi:
- // This looks like a variable declaration. The type is probably missing.
- // We're done parsing decl-specifiers.
- return false;
-
case tok::l_paren: {
// static x(4); // 'x' is not a type
// x(int n); // 'x' is not a type
@@ -2178,12 +2170,37 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
ConsumeToken();
TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false);
PA.Revert();
- if (TPR == TPResult::False())
- return false;
- // The identifier is followed by a parenthesized declarator.
- // It's supposed to be a type.
- break;
+
+ if (TPR != TPResult::False()) {
+ // The identifier is followed by a parenthesized declarator.
+ // It's supposed to be a type.
+ break;
+ }
+
+ // If we're in a context where we could be declaring a constructor,
+ // check whether this is a constructor declaration with a bogus name.
+ if (DSC == DSC_class || (DSC == DSC_top_level && SS)) {
+ IdentifierInfo *II = Tok.getIdentifierInfo();
+ if (Actions.isCurrentClassNameTypo(II, SS)) {
+ Diag(Loc, diag::err_constructor_bad_name)
+ << Tok.getIdentifierInfo() << II
+ << FixItHint::CreateReplacement(Tok.getLocation(), II->getName());
+ Tok.setIdentifierInfo(II);
+ }
+ }
+ // Fall through.
}
+ case tok::comma:
+ case tok::equal:
+ case tok::kw_asm:
+ case tok::l_brace:
+ case tok::l_square:
+ case tok::semi:
+ // This looks like a variable or function declaration. The type is
+ // probably missing. We're done parsing decl-specifiers.
+ if (SS)
+ AnnotateScopeToken(*SS, /*IsNewAnnotation*/false);
+ return false;
default:
// This is probably supposed to be a type. This includes cases like:
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 6ec344d1e3c..655c9e2c3d0 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -1227,6 +1227,32 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *,
return false;
}
+/// \brief Determine whether the identifier II is a typo for the name of
+/// the class type currently being defined. If so, update it to the identifier
+/// that should have been used.
+bool Sema::isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS) {
+ assert(getLangOpts().CPlusPlus && "No class names in C!");
+
+ if (!getLangOpts().SpellChecking)
+ return false;
+
+ CXXRecordDecl *CurDecl;
+ if (SS && SS->isSet() && !SS->isInvalid()) {
+ DeclContext *DC = computeDeclContext(*SS, true);
+ CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC);
+ } else
+ CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);
+
+ if (CurDecl && CurDecl->getIdentifier() && II != CurDecl->getIdentifier() &&
+ 3 * II->getName().edit_distance(CurDecl->getIdentifier()->getName())
+ < II->getLength()) {
+ II = CurDecl->getIdentifier();
+ return true;
+ }
+
+ return false;
+}
+
/// \brief Determine whether the given class is a base class of the given
/// class, including looking at dependent bases.
static bool findCircularInheritance(const CXXRecordDecl *Class,
OpenPOWER on IntegriCloud