Index: cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp =================================================================== --- cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp +++ cfe/trunk/lib/Parse/ParseCXXInlineMethods.cpp @@ -832,22 +832,30 @@ } } - 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 @@ // 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). Index: cfe/trunk/test/CodeCompletion/ctor-initializer.cpp =================================================================== --- cfe/trunk/test/CodeCompletion/ctor-initializer.cpp +++ cfe/trunk/test/CodeCompletion/ctor-initializer.cpp @@ -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 @@ }; 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 @@ { } 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; +};