r285883 - Fix heuristics skipping invalid ctor-initializers with C++11

Olivier Goffart via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 3 00:36:18 PDT 2016


Author: ogoffart
Date: Thu Nov  3 02:36:17 2016
New Revision: 285883

URL: http://llvm.org/viewvc/llvm-project?rev=285883&view=rev
Log:
Fix heuristics skipping invalid ctor-initializers with C++11

Use better heuristics to detect if a '{' might be the start of the constructor body
or not. Especially when there is a completion token.

Fix the test 'test/CodeCompletion/ctor-initializer.cpp ' when clang defaults to c++11

The problem was is how we recover invalid code in the ctor-init part as we skip the
function body. In particular, we want to know if a '{' is the begining of the body.
In C++03, we always consider it as the beginng of the body. The problem was that in
C++11, it may be the start of an initializer, so we skip over it, causing further
parse errors later. (It is important that we are able to parse correctly the rest
of the class definition, to know what are the class member, for example)

This commit is improving the heuristics to decide if the '{' is starting a function
body. The rules are the following: If we are not in a template argument, and that the
previous tokens are not an identifier, or a >, then it is much more likely to be the
function body. We verify that further by checking the token after the matching '}'

The commit also fix the behavior when there is a code_completion token in the
ctor-initializers.

Differential Revision: https://reviews.llvm.org/D21502

Modified:
    cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
    cfe/trunk/test/CodeCompletion/ctor-initializer.cpp

Modified: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp?rev=285883&r1=285882&r2=285883&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp (original)
+++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp Thu Nov  3 02:36:17 2016
@@ -832,22 +832,30 @@ bool Parser::ConsumeAndStoreFunctionProl
         }
       }
 
-      if (Tok.isOneOf(tok::identifier, tok::kw_template)) {
+      if (Tok.is(tok::identifier)) {
         Toks.push_back(Tok);
         ConsumeToken();
-      } else if (Tok.is(tok::code_completion)) {
-        Toks.push_back(Tok);
-        ConsumeCodeCompletionToken();
-        // Consume the rest of the initializers permissively.
-        // FIXME: We should be able to perform code-completion here even if
-        //        there isn't a subsequent '{' token.
-        MightBeTemplateArgument = true;
-        break;
       } else {
         break;
       }
     } while (Tok.is(tok::coloncolon));
 
+    if (Tok.is(tok::code_completion)) {
+      Toks.push_back(Tok);
+      ConsumeCodeCompletionToken();
+      if (Tok.isOneOf(tok::identifier, tok::coloncolon, tok::kw_decltype)) {
+        // Could be the start of another member initializer (the ',' has not
+        // been written yet)
+        continue;
+      }
+    }
+
+    if (Tok.is(tok::comma)) {
+      // The initialization is missing, we'll diagnose it later.
+      Toks.push_back(Tok);
+      ConsumeToken();
+      continue;
+    }
     if (Tok.is(tok::less))
       MightBeTemplateArgument = true;
 
@@ -888,6 +896,26 @@ bool Parser::ConsumeAndStoreFunctionProl
       // means the initializer is malformed; we'll diagnose it later.
       if (!getLangOpts().CPlusPlus11)
         return false;
+
+      const Token &PreviousToken = Toks[Toks.size() - 2];
+      if (!MightBeTemplateArgument &&
+          !PreviousToken.isOneOf(tok::identifier, tok::greater,
+                                 tok::greatergreater)) {
+        // If the opening brace is not preceded by one of these tokens, we are
+        // missing the mem-initializer-id. In order to recover better, we need
+        // to use heuristics to determine if this '{' is most likely the
+        // begining of a brace-init-list or the function body.
+        // Check the token after the corresponding '}'.
+        TentativeParsingAction PA(*this);
+        if (SkipUntil(tok::r_brace) &&
+            !Tok.isOneOf(tok::comma, tok::ellipsis, tok::l_brace)) {
+          // Consider there was a malformed initializer and this is the start
+          // of the function body. We'll diagnose it later.
+          PA.Revert();
+          return false;
+        }
+        PA.Revert();
+      }
     }
 
     // Grab the initializer (or the subexpression of the template argument).

Modified: cfe/trunk/test/CodeCompletion/ctor-initializer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeCompletion/ctor-initializer.cpp?rev=285883&r1=285882&r2=285883&view=diff
==============================================================================
--- cfe/trunk/test/CodeCompletion/ctor-initializer.cpp (original)
+++ cfe/trunk/test/CodeCompletion/ctor-initializer.cpp Thu Nov  3 02:36:17 2016
@@ -1,11 +1,13 @@
 struct Base1 {
   Base1() : {}
-  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:2:12 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
+  // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:2:12 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
+  // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:2:12 %s -o - | FileCheck -check-prefix=CHECK-CC1 %s
   // CHECK-CC1: COMPLETION: Pattern : member1(<#args#>)
   // CHECK-CC1: COMPLETION: Pattern : member2(<#args#>
 
   Base1(int) : member1(123), {}
-  // RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:7:30 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
+  // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:8:30 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
+  // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:8:30 %s -o - | FileCheck -check-prefix=CHECK-CC2 %s
   // CHECK-CC2-NOT: COMPLETION: Pattern : member1(<#args#>)
   // CHECK-CC2: COMPLETION: Pattern : member2(<#args#>
 
@@ -21,14 +23,16 @@ struct Derived : public Base1 {
 };
 
 Derived::Derived() : {}
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:23:22 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:25:22 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:25:22 %s -o - | FileCheck -check-prefix=CHECK-CC3 %s
 // CHECK-CC3: COMPLETION: Pattern : Base1(<#args#>)
 // CHECK-CC3: COMPLETION: Pattern : deriv1(<#args#>)
 
 Derived::Derived(int) try : {
 } catch (...) {
 }
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:28:29 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:31:29 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:31:29 %s -o - | FileCheck -check-prefix=CHECK-CC4 %s
 // CHECK-CC4: COMPLETION: Pattern : Base1(<#args#>)
 // CHECK-CC4: COMPLETION: Pattern : deriv1(<#args#>)
 
@@ -36,6 +40,23 @@ Derived::Derived(float) try : Base1(),
 {
 } catch (...) {
 }
-// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:35:39 %s -o - | FileCheck -check-prefix=CHECK-CC5 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:39:39 %s -o - | FileCheck -check-prefix=CHECK-CC5 %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:39:39 %s -o - | FileCheck -check-prefix=CHECK-CC5 %s
 // CHECK-CC5-NOT: COMPLETION: Pattern : Base1(<#args#>)
 // CHECK-CC5: COMPLETION: Pattern : deriv1(<#args#>)
+
+struct A {
+  A() : , member2() {}
+  // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:49:9 %s -o - | FileCheck -check-prefix=CHECK-CC6 %s
+  // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:49:9 %s -o - | FileCheck -check-prefix=CHECK-CC6 %s
+  // CHECK-CC6: COMPLETION: Pattern : member1(<#args#>
+  int member1, member2;
+};
+
+struct B {
+  B() : member2() {}
+  // RUN: %clang_cc1 -fsyntax-only -std=c++98 -code-completion-at=%s:57:9 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
+  // RUN: %clang_cc1 -fsyntax-only -std=c++14 -code-completion-at=%s:57:9 %s -o - | FileCheck -check-prefix=CHECK-CC7 %s
+  // CHECK-CC7: COMPLETION: Pattern : member1(<#args#>
+  int member1, member2;
+};




More information about the cfe-commits mailing list