<div dir="ltr">Awesome! Thanks Richard!<div><br></div><div>-- Sean Silva</div></div><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Oct 14, 2013 at 8:00 PM, Richard Smith <span dir="ltr"><<a href="mailto:richard-llvm@metafoo.co.uk" target="_blank">richard-llvm@metafoo.co.uk</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rsmith<br>
Date: Mon Oct 14 19:00:26 2013<br>
New Revision: 192644<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=192644&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=192644&view=rev</a><br>
Log:<br>
PR17567: Improve diagnostic for a mistyped constructor name. If we see something<br>
that looks like a function declaration, except that it's missing a return type,<br>
try typo-correcting it to the relevant constructor name.<br>
<br>
In passing, fix a bug where the missing-type-specifier recovery codepath would<br>
drop a preceding scope specifier on the floor, leading to follow-on diagnostics<br>
and incorrect recovery for the auto-in-c++98 hack.<br>
<br>
Modified:<br>
cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td<br>
cfe/trunk/include/clang/Sema/Sema.h<br>
cfe/trunk/lib/Parse/ParseDecl.cpp<br>
cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
cfe/trunk/test/CXX/drs/dr1xx.cpp<br>
cfe/trunk/test/Parser/cxx-decl.cpp<br>
cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp<br>
cfe/trunk/test/SemaCXX/nested-name-spec.cpp<br>
cfe/trunk/test/SemaTemplate/alias-nested-nontag.cpp<br>
<br>
Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=192644&r1=192643&r2=192644&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=192644&r1=192643&r2=192644&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Mon Oct 14 19:00:26 2013<br>
@@ -482,6 +482,8 @@ def err_expected_rbrace_or_comma : Error<br>
def err_expected_rsquare_or_comma : Error<"expected ']' or ','">;<br>
def err_using_namespace_in_class : Error<<br>
"'using namespace' is not allowed in classes">;<br>
+def err_constructor_bad_name : Error<<br>
+ "missing return type for function %0; did you mean the constructor name %1?">;<br>
def err_destructor_tilde_identifier : Error<<br>
"expected a class name after '~' to name a destructor">;<br>
def err_destructor_template_id : Error<<br>
<br>
Modified: cfe/trunk/include/clang/Sema/Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=192644&r1=192643&r2=192644&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=192644&r1=192643&r2=192644&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/Sema/Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Oct 14 19:00:26 2013<br>
@@ -4606,6 +4606,7 @@ public:<br>
//<br>
bool isCurrentClassName(const IdentifierInfo &II, Scope *S,<br>
const CXXScopeSpec *SS = 0);<br>
+ bool isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS);<br>
<br>
bool ActOnAccessSpecifier(AccessSpecifier Access,<br>
SourceLocation ASLoc,<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=192644&r1=192643&r2=192644&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=192644&r1=192643&r2=192644&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Oct 14 19:00:26 2013<br>
@@ -2095,6 +2095,8 @@ bool Parser::ParseImplicitInt(DeclSpec &<br>
DS.getStorageClassSpec() == DeclSpec::SCS_auto) {<br>
// Don't require a type specifier if we have the 'auto' storage class<br>
// specifier in C++98 -- we'll promote it to a type specifier.<br>
+ if (SS)<br>
+ AnnotateScopeToken(*SS, /*IsNewAnnotation*/false);<br>
return false;<br>
}<br>
<br>
@@ -2156,16 +2158,6 @@ bool Parser::ParseImplicitInt(DeclSpec &<br>
// Look ahead to the next token to try to figure out what this declaration<br>
// was supposed to be.<br>
switch (NextToken().getKind()) {<br>
- case tok::comma:<br>
- case tok::equal:<br>
- case tok::kw_asm:<br>
- case tok::l_brace:<br>
- case tok::l_square:<br>
- case tok::semi:<br>
- // This looks like a variable declaration. The type is probably missing.<br>
- // We're done parsing decl-specifiers.<br>
- return false;<br>
-<br>
case tok::l_paren: {<br>
// static x(4); // 'x' is not a type<br>
// x(int n); // 'x' is not a type<br>
@@ -2178,12 +2170,37 @@ bool Parser::ParseImplicitInt(DeclSpec &<br>
ConsumeToken();<br>
TPResult TPR = TryParseDeclarator(/*mayBeAbstract*/false);<br>
PA.Revert();<br>
- if (TPR == TPResult::False())<br>
- return false;<br>
- // The identifier is followed by a parenthesized declarator.<br>
- // It's supposed to be a type.<br>
- break;<br>
+<br>
+ if (TPR != TPResult::False()) {<br>
+ // The identifier is followed by a parenthesized declarator.<br>
+ // It's supposed to be a type.<br>
+ break;<br>
+ }<br>
+<br>
+ // If we're in a context where we could be declaring a constructor,<br>
+ // check whether this is a constructor declaration with a bogus name.<br>
+ if (DSC == DSC_class || (DSC == DSC_top_level && SS)) {<br>
+ IdentifierInfo *II = Tok.getIdentifierInfo();<br>
+ if (Actions.isCurrentClassNameTypo(II, SS)) {<br>
+ Diag(Loc, diag::err_constructor_bad_name)<br>
+ << Tok.getIdentifierInfo() << II<br>
+ << FixItHint::CreateReplacement(Tok.getLocation(), II->getName());<br>
+ Tok.setIdentifierInfo(II);<br>
+ }<br>
+ }<br>
+ // Fall through.<br>
}<br>
+ case tok::comma:<br>
+ case tok::equal:<br>
+ case tok::kw_asm:<br>
+ case tok::l_brace:<br>
+ case tok::l_square:<br>
+ case tok::semi:<br>
+ // This looks like a variable or function declaration. The type is<br>
+ // probably missing. We're done parsing decl-specifiers.<br>
+ if (SS)<br>
+ AnnotateScopeToken(*SS, /*IsNewAnnotation*/false);<br>
+ return false;<br>
<br>
default:<br>
// This is probably supposed to be a type. This includes cases like:<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=192644&r1=192643&r2=192644&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=192644&r1=192643&r2=192644&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Oct 14 19:00:26 2013<br>
@@ -1227,6 +1227,32 @@ bool Sema::isCurrentClassName(const Iden<br>
return false;<br>
}<br>
<br>
+/// \brief Determine whether the identifier II is a typo for the name of<br>
+/// the class type currently being defined. If so, update it to the identifier<br>
+/// that should have been used.<br>
+bool Sema::isCurrentClassNameTypo(IdentifierInfo *&II, const CXXScopeSpec *SS) {<br>
+ assert(getLangOpts().CPlusPlus && "No class names in C!");<br>
+<br>
+ if (!getLangOpts().SpellChecking)<br>
+ return false;<br>
+<br>
+ CXXRecordDecl *CurDecl;<br>
+ if (SS && SS->isSet() && !SS->isInvalid()) {<br>
+ DeclContext *DC = computeDeclContext(*SS, true);<br>
+ CurDecl = dyn_cast_or_null<CXXRecordDecl>(DC);<br>
+ } else<br>
+ CurDecl = dyn_cast_or_null<CXXRecordDecl>(CurContext);<br>
+<br>
+ if (CurDecl && CurDecl->getIdentifier() && II != CurDecl->getIdentifier() &&<br>
+ 3 * II->getName().edit_distance(CurDecl->getIdentifier()->getName())<br>
+ < II->getLength()) {<br>
+ II = CurDecl->getIdentifier();<br>
+ return true;<br>
+ }<br>
+<br>
+ return false;<br>
+}<br>
+<br>
/// \brief Determine whether the given class is a base class of the given<br>
/// class, including looking at dependent bases.<br>
static bool findCircularInheritance(const CXXRecordDecl *Class,<br>
<br>
Modified: cfe/trunk/test/CXX/drs/dr1xx.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr1xx.cpp?rev=192644&r1=192643&r2=192644&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/drs/dr1xx.cpp?rev=192644&r1=192643&r2=192644&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CXX/drs/dr1xx.cpp (original)<br>
+++ cfe/trunk/test/CXX/drs/dr1xx.cpp Mon Oct 14 19:00:26 2013<br>
@@ -223,14 +223,18 @@ namespace dr122 { // dr122: yes<br>
// dr124: dup 201<br>
<br>
// dr125: yes<br>
-struct dr125_A { struct dr125_B {}; };<br>
+struct dr125_A { struct dr125_B {}; }; // expected-note {{here}}<br>
dr125_A::dr125_B dr125_C();<br>
namespace dr125_B { dr125_A dr125_C(); }<br>
namespace dr125 {<br>
struct X {<br>
friend dr125_A::dr125_B (::dr125_C)(); // ok<br>
friend dr125_A (::dr125_B::dr125_C)(); // ok<br>
- friend dr125_A::dr125_B::dr125_C(); // expected-error {{requires a type specifier}}<br>
+ friend dr125_A::dr125_B::dr125_C(); // expected-error {{did you mean the constructor name 'dr125_B'?}}<br>
+ // expected-warning@-1 {{missing exception specification}}<br>
+#if __cplusplus >= 201103L<br>
+ // expected-error@-3 {{follows constexpr declaration}} expected-note@-10 {{here}}<br>
+#endif<br>
};<br>
}<br>
<br>
<br>
Modified: cfe/trunk/test/Parser/cxx-decl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-decl.cpp?rev=192644&r1=192643&r2=192644&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-decl.cpp?rev=192644&r1=192643&r2=192644&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/Parser/cxx-decl.cpp (original)<br>
+++ cfe/trunk/test/Parser/cxx-decl.cpp Mon Oct 14 19:00:26 2013<br>
@@ -223,6 +223,15 @@ void foo() {<br>
}<br>
}<br>
<br>
+namespace PR17567 {<br>
+ struct Foobar { // expected-note 2{{declared here}}<br>
+ FooBar(); // expected-error {{missing return type for function 'FooBar'; did you mean the constructor name 'Foobar'?}}<br>
+ ~FooBar(); // expected-error {{expected the class name after '~' to name a destructor}}<br>
+ };<br>
+ FooBar::FooBar() {} // expected-error {{undeclared}} expected-error {{missing return type}}<br>
+ FooBar::~FooBar() {} // expected-error {{undeclared}} expected-error {{expected the class name}}<br>
+}<br>
+<br>
// PR8380<br>
extern "" // expected-error {{unknown linkage language}}<br>
test6a { ;// expected-error {{C++ requires a type specifier for all declarations}} \<br>
<br>
Modified: cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp?rev=192644&r1=192643&r2=192644&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp?rev=192644&r1=192643&r2=192644&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp (original)<br>
+++ cfe/trunk/test/Parser/cxx0x-in-cxx98.cpp Mon Oct 14 19:00:26 2013<br>
@@ -21,3 +21,10 @@ void NewBracedInitList() {<br>
// A warning on this would be sufficient once we can handle it correctly.<br>
new int {}; // expected-error {{}}<br>
}<br>
+<br>
+struct Auto {<br>
+ static int n;<br>
+};<br>
+auto Auto::n = 0; // expected-warning {{'auto' type specifier is a C++11 extension}}<br>
+auto Auto::m = 0; // expected-error {{no member named 'm' in 'Auto'}}<br>
+ // expected-warning@-1 {{'auto' type specifier is a C++11 extension}}<br>
<br>
Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=192644&r1=192643&r2=192644&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=192644&r1=192643&r2=192644&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Mon Oct 14 19:00:26 2013<br>
@@ -167,9 +167,7 @@ void N::f() { } // okay<br>
struct Y; // expected-note{{forward declaration of 'Y'}}<br>
Y::foo y; // expected-error{{incomplete type 'Y' named in nested name specifier}}<br>
<br>
-X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}} \<br>
- // expected-error{{C++ requires a type specifier for all declarations}} \<br>
- // expected-error{{only constructors take base initializers}}<br>
+X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}}<br>
<br>
struct foo_S {<br>
static bool value;<br>
<br>
Modified: cfe/trunk/test/SemaTemplate/alias-nested-nontag.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/alias-nested-nontag.cpp?rev=192644&r1=192643&r2=192644&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/alias-nested-nontag.cpp?rev=192644&r1=192643&r2=192644&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/SemaTemplate/alias-nested-nontag.cpp (original)<br>
+++ cfe/trunk/test/SemaTemplate/alias-nested-nontag.cpp Mon Oct 14 19:00:26 2013<br>
@@ -2,5 +2,4 @@<br>
<br>
template<typename T> using Id = T; // expected-note {{type alias template 'Id' declared here}}<br>
struct U { static Id<int> V; };<br>
-Id<int> ::U::V; // expected-error {{type 'Id<int>' (aka 'int') cannot be used prior to '::' because it has no members}} \<br>
- expected-error {{C++ requires a type specifier}}<br>
+Id<int> ::U::V; // expected-error {{type 'Id<int>' (aka 'int') cannot be used prior to '::' because it has no members}}<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>