Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -2618,13 +2618,43 @@ if (Tok.is(tok::colon)) { ParseBaseClause(TagDecl); - if (!Tok.is(tok::l_brace)) { - Diag(Tok, diag::err_expected_lbrace_after_base_specifiers); - - if (TagDecl) - Actions.ActOnTagDefinitionError(getCurScope(), TagDecl); - return; + bool SuggestFixIt = false; + SourceLocation BraceLoc = PP.getLocForEndOfToken(PrevTokLocation); + if (Tok.isAtStartOfLine()) { + switch (Tok.getKind()) { + case tok::kw_private: + case tok::kw_protected: + case tok::kw_public: + SuggestFixIt = NextToken().getKind() == tok::colon; + break; + case tok::kw_static_assert: + case tok::r_brace: + case tok::kw_using: + // base-clause can have simple-template-id; 'template' can't be there + case tok::kw_template: + SuggestFixIt = true; + break; + case tok::identifier: + SuggestFixIt = isConstructorDeclarator(true); + break; + default: + SuggestFixIt = isCXXSimpleDeclaration(/*AllowForRangeDecl=*/false); + break; + } + } + DiagnosticBuilder LBraceDiag = + Diag(BraceLoc, diag::err_expected_lbrace_after_base_specifiers); + if (SuggestFixIt) { + LBraceDiag << FixItHint::CreateInsertion(BraceLoc, " {"); + // Try recovering from missing { after base-clause. + PP.EnterToken(Tok); + Tok.setKind(tok::l_brace); + } else { + if (TagDecl) + Actions.ActOnTagDefinitionError(getCurScope(), TagDecl); + return; + } } } Index: test/FixIt/fixit.cpp =================================================================== --- test/FixIt/fixit.cpp +++ test/FixIt/fixit.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -pedantic -Wall -Wno-comment -verify -fcxx-exceptions -x c++ %s -// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ %s 2>&1 | FileCheck %s +// RUN: not %clang_cc1 -fsyntax-only -fdiagnostics-parseable-fixits -x c++ -std=c++11 %s 2>&1 | FileCheck %s // RUN: cp %s %t // RUN: not %clang_cc1 -pedantic -Wall -Wno-comment -fcxx-exceptions -fixit -x c++ %t // RUN: %clang_cc1 -fsyntax-only -pedantic -Wall -Werror -Wno-comment -fcxx-exceptions -x c++ %t @@ -340,3 +340,37 @@ return c->a; // expected-error {{member reference type 'PR15045::Cl0' is not a pointer; maybe you meant to use '.'?}} } } + +namespace curly_after_base_clause { +struct A { void f(); }; +struct B : A // expected-error{{expected '{' after base class list}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {" + int i; +}; +struct C : A // expected-error{{expected '{' after base class list}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {" + using A::f; +}; +struct D : A // expected-error{{expected '{' after base class list}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {" + protected: +}; +struct E : A // expected-error{{expected '{' after base class list}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {" + template struct inner { }; +}; +struct F : A // expected-error{{expected '{' after base class list}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {" + F() { } +}; +#if __cplusplus >= 201103L +struct G : A // expected-error{{expected '{' after base class list}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {" + constexpr G(int) { } +}; +struct H : A // expected-error{{expected '{' after base class list}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-1]]:13-[[@LINE-1]]:13}:" {" + static_assert(true, ""); +}; +#endif +} Index: test/Parser/cxx-template-decl.cpp =================================================================== --- test/Parser/cxx-template-decl.cpp +++ test/Parser/cxx-template-decl.cpp @@ -210,3 +210,18 @@ } } + +namespace broken_baseclause { +template +struct base { }; + +struct t1 : base