From: Nico Weber Date: Sun, 28 Dec 2014 23:24:02 +0000 (+0000) Subject: Don't crash on surprising tokens in default parameter template lists. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=462b18e34fb2e664648b680d56c2d1d5c9a190a0;p=clang Don't crash on surprising tokens in default parameter template lists. Fixes this snippet from SLi's afl fuzzer output: class { i (x = <, enum This parsed i as a function, x as a paramter, and the stuff after < as a template list. This then called TryConsumeDeclarationSpecifier() which called TryAnnotateCXXScopeToken() without checking the preconditions of this function. Check them before calling, like all other callers of TryAnnotateCXXScopeToken() do. A more readable reproducer that causes the same crash is class { void i(int x = MyTemplateClass::foo()); }; The reduced version used an eof token as surprising token, but kw_int works just as well to repro and is easier to insert into a test file. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@224906 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index e39f2f1627..7c9cceb12b 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -1019,7 +1019,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks, case CIK_DefaultArgument: bool InvalidAsDeclaration = false; Result = TryParseParameterDeclarationClause( - &InvalidAsDeclaration, /*VersusTemplateArgument*/true); + &InvalidAsDeclaration, /*VersusTemplateArgument=*/true); // If this is an expression or a declaration with a missing // 'typename', assume it's not a declaration. if (Result == TPResult::Ambiguous && InvalidAsDeclaration) diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 1f39c25590..929242f200 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -195,7 +195,9 @@ Parser::TPResult Parser::TryConsumeDeclarationSpecifier() { } } - if (TryAnnotateCXXScopeToken()) + if ((Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + Tok.is(tok::kw_decltype) || Tok.is(tok::annot_template_id)) && + TryAnnotateCXXScopeToken()) return TPResult::Error; if (Tok.is(tok::annot_cxxscope)) ConsumeToken(); diff --git a/test/Parser/cxx-member-initializers.cpp b/test/Parser/cxx-member-initializers.cpp index ff8c880a18..461810c62f 100644 --- a/test/Parser/cxx-member-initializers.cpp +++ b/test/Parser/cxx-member-initializers.cpp @@ -79,3 +79,29 @@ namespace PR16480 { Errs(X<2>) : decltype(X<0> // expected-note {{to match this '('}} }; // expected-error {{expected ')'}} } + +template struct C { + int f() { return 4; } + class C1 {}; +}; + +class D {}; +namespace N { +struct E { + class F {}; +}; +} + +class G { + // These are all valid: + void f(int x = C().f()) {} + void g(int x = C().f()) {} + void h(int x = C().f()) {} + void i(int x = C().f()) {} + void j(int x = C().f()) {} + void k(int x = C>().f()) {} + void l(int x = C::C1>().f()) {} + + // This isn't, but it shouldn't crash. The diagnostics don't matter much. + void m(int x = C().f()) {} // expected-error {{declaration of anonymous union must be a definition}} +}; // expected-error {{expected a type}}