]> granicus.if.org Git - clang/commitdiff
Don't crash on surprising tokens in default parameter template lists.
authorNico Weber <nicolasweber@gmx.de>
Sun, 28 Dec 2014 23:24:02 +0000 (23:24 +0000)
committerNico Weber <nicolasweber@gmx.de>
Sun, 28 Dec 2014 23:24:02 +0000 (23:24 +0000)
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<int, union int>::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

lib/Parse/ParseCXXInlineMethods.cpp
lib/Parse/ParseTentative.cpp
test/Parser/cxx-member-initializers.cpp

index e39f2f1627bc6151c367e9bee157113db55fa481..7c9cceb12bcfd6eb4937e12266cd2c0ff27daebc 100644 (file)
@@ -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)
index 1f39c25590d0efe72ec16fe78c6d9d11d4a26710..929242f2004f763f19f72efba4dd48f0a89f1f36 100644 (file)
@@ -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();
index ff8c880a184969690b8cde7609aaa5b5ae64dff8..461810c62fbb8268a2ab77459a12a35deba7101c 100644 (file)
@@ -79,3 +79,29 @@ namespace PR16480 {
     Errs(X<2>) : decltype(X<0> // expected-note {{to match this '('}}
   }; // expected-error {{expected ')'}}
 }
+
+template <class U, class V> 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<int, D>().f()) {}
+  void g(int x = C<int, ::D>().f()) {}
+  void h(int x = C<int, N::E>().f()) {}
+  void i(int x = C<int, ::N::E>().f()) {}
+  void j(int x = C<int, decltype(N::E())::F>().f()) {}
+  void k(int x = C<int, C<int, int>>().f()) {}
+  void l(int x = C<int, C<int, int>::C1>().f()) {}
+
+  // This isn't, but it shouldn't crash. The diagnostics don't matter much.
+  void m(int x = C<int, union int>().f()) {} // expected-error {{declaration of anonymous union must be a definition}}
+}; // expected-error {{expected a type}}