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