[prev in list] [next in list] [prev in thread] [next in thread] 

List:       cfe-dev
Subject:    [cfe-dev] [PATCH] Fix parsing comma in default arguments.
From:       Olivier Goffart <ogoffart () kde ! org>
Date:       2013-06-12 9:15:40
Message-ID: 2031045.CKME4JiHAo () gargamel
[Download RAW message or body]

Hi, 

About a moth ago I posted a patch on cfe-commits, but i did not get any reply,
so I am reposting to this list.

The patch fixes the bug
http://llvm.org/bugs/show_bug.cgi?id=13657

It fixes parsing of code such as:

struct S {
 void foo(map<int, int> m = map<int, int>()) ;
};

Or, in C++11:

struct S {
  map<int, int> m = map<int, int>();
};

Link to my post on cfe-commits:
http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20130527/080812.html

-- 
Olivier
["0001-Fix-parsing-comma-in-default-argument.patch" (0001-Fix-parsing-comma-in-default-argument.patch)]

From 72b9a23b3df6db5069779af664ee28d4d2572a6b Mon Sep 17 00:00:00 2001
From: Olivier Goffart <ogoffart@woboq.com>
Date: Sun, 19 May 2013 11:24:54 +0200
Subject: [PATCH] Fix parsing comma in default argument

http://llvm.org/bugs/show_bug.cgi?id=13657
---
 include/clang/Parse/Parser.h              |  1 +
 lib/Parse/ParseCXXInlineMethods.cpp       | 44 +++++++++++++++++++--
 lib/Parse/ParseTentative.cpp              | 65 +++++++++++++++++++++++++++++++
 test/Parser/cxx-default-args.cpp          | 17 ++++++++
 test/Parser/cxx0x-member-initializers.cpp | 10 +++++
 5 files changed, 133 insertions(+), 4 deletions(-)

diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h
index 1029a90..f2afa06 100644
--- a/include/clang/Parse/Parser.h
+++ b/include/clang/Parse/Parser.h
@@ -1821,6 +1821,7 @@ private:
   TPResult TryParseParameterDeclarationClause(bool *InvalidAsDeclaration = 0);
   TPResult TryParseFunctionDeclarator();
   TPResult TryParseBracketDeclarator();
+  TPResult TryParseParameterDeclarationWithDefaultArgument();
 
 public:
   TypeResult ParseTypeName(SourceRange *Range = 0,
diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp
index 5fc4189..2868bfc 100644
--- a/lib/Parse/ParseCXXInlineMethods.cpp
+++ b/lib/Parse/ParseCXXInlineMethods.cpp
@@ -563,14 +563,32 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
   // We always want this function to consume at least one token if the first
   // token isn't T and if not at EOF.
   bool isFirstTokenConsumed = true;
+  int TemplateLevel = 0;
   while (1) {
     // If we found one of the tokens, stop and return true.
     if (Tok.is(T1) || Tok.is(T2)) {
-      if (ConsumeFinalToken) {
-        Toks.push_back(Tok);
-        ConsumeAnyToken();
+      bool Done = true;
+      if (Tok.is(tok::comma) && TemplateLevel > 0) {
+        // Special case for comma: is it the separation of template parameters,
+        // or is it the separation of function parameters?
+        TentativeParsingAction TPA(*this);
+        ConsumeToken();
+        if (T2 == tok::r_paren) {
+          // We are currently parsing the default argument of a function
+          Done = TryParseParameterDeclarationWithDefaultArgument() == TPResult::True();
+        } else {
+          // We are currently parsing a NSDMI
+          Done = TryParseDeclarator(false) == TPResult::Ambiguous();
+        }
+        TPA.Revert();
+      }
+      if (Done) {
+        if (ConsumeFinalToken) {
+          Toks.push_back(Tok);
+          ConsumeAnyToken();
+        }
+        return true;
       }
-      return true;
     }
 
     switch (Tok.getKind()) {
@@ -597,6 +615,24 @@ bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
       ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
       break;
 
+    case tok::less:
+      TemplateLevel++;
+      Toks.push_back(Tok);
+      ConsumeToken();
+      break;
+    case tok::greater:
+      if (TemplateLevel)
+        TemplateLevel--;
+      Toks.push_back(Tok);
+      ConsumeToken();
+      break;
+    case tok::greatergreater:
+      if (TemplateLevel)
+        TemplateLevel-=2;
+      Toks.push_back(Tok);
+      ConsumeToken();
+      break;
+
     // Okay, we found a ']' or '}' or ')', which we think should be balanced.
     // Since the user wasn't looking for this token (if they were, it would
     // already be handled), this isn't balanced.  If there is a LHS token at a
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index dff3b64..4541a7f 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -1530,6 +1530,71 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration) {
   return TPResult::Ambiguous();
 }
 
+/// try to disambiguate between a comma between template arguments and a comma
+/// between function parameters.
+/// The comma was already parsed.
+///
+/// BracketDepth is the depth in angle bracket we have.
+///
+Parser::TPResult Parser::TryParseParameterDeclarationWithDefaultArgument() {
+  // An attribute-specifier-seq here is a sign of a function declarator.
+  if (isCXX11AttributeSpecifier(/*Disambiguate*/false,
+                                /*OuterMightBeMessageSend*/true))
+    return TPResult::True();
+
+  ParsedAttributes attrs(AttrFactory);
+  MaybeParseMicrosoftAttributes(attrs);
+
+  TPResult TPR = TryParseDeclarationSpecifier();
+  if (TPR == TPResult::Error() || TPR == TPResult::False())
+    return TPR;
+
+  // Now try to find the '=' sign of the next parameter, or the '>' of the end
+  // of the template parameter list.
+  tok::TokenKind TokArray[] = {tok::equal, tok::less, tok::comma,
+                               tok::greater, tok::greatergreater };
+
+  int AngleBracketDepth = 0;
+
+  while (SkipUntil(TokArray, /*StopAtSemi*/ true, /*DontConsume*/ true)) {
+
+    switch(Tok.getKind()) {
+    case tok::equal:
+      // The start of the default argument: it was an argument list.
+      return TPResult::True();
+
+    case tok::less:
+      AngleBracketDepth++;
+      break;
+
+    case tok::greater:
+      AngleBracketDepth--;
+      break;
+
+    case tok::greatergreater:
+      if(getLangOpts().CPlusPlus11)
+        AngleBracketDepth -= 2;
+      break;
+
+    case tok::comma:
+      // another comma can only appears in template parameter
+      if (!AngleBracketDepth)
+        return TPResult::False();
+
+    default:
+        assert(!"unexpected token");
+    }
+
+    // There cannot be '<' if not a template argument.
+    if (AngleBracketDepth < 0)
+     return TPResult::False();
+
+    ConsumeToken();
+  }
+
+  return TPResult::Error();
+}
+
 /// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue
 /// parsing as a function declarator.
 /// If TryParseFunctionDeclarator fully parsed the function declarator, it will
diff --git a/test/Parser/cxx-default-args.cpp b/test/Parser/cxx-default-args.cpp
index 7fe8474..19b50cb 100644
--- a/test/Parser/cxx-default-args.cpp
+++ b/test/Parser/cxx-default-args.cpp
@@ -14,3 +14,20 @@ typedef struct Inst {
 struct X {
   void f(int x = 1:); // expected-error {{unexpected end of default argument expression}}
 };
+
+// PR13657
+struct T {
+  template <typename A, typename B> struct T1 { enum {V};};
+  template <int A, int B> struct T2 { enum {V}; };
+  template <int, int> static int func(int);
+
+
+  void f1(T1<int, int> = T1<int, int>());
+  void f2(T1<int, double> = T1<int, double>(), T2<0, 5> = T2<0, 5>());
+  void f3(int a = T2<0, (T1<int, int>::V > 10) ? 5 : 6>::V, bool b = 4<5 );
+  void f4(bool a = 1 < 0, bool b = 2 > 0 );
+  void f5(bool a = 1 > T2<0, 0>::V, bool b = T1<int,int>::V < 3, int c = 0);
+  void f6(bool a = T2<0,3>::V < 4, bool b = 4 > T2<0,3>::V);
+  void f7(bool a = T1<int, bool>::V < 3);
+  void f8(int = func<0,1<2>(0), int = 1<0, T1<int,int>(int) = 0);
+};
\ No newline at end of file
diff --git a/test/Parser/cxx0x-member-initializers.cpp b/test/Parser/cxx0x-member-initializers.cpp
index a324f97..43e99b1 100644
--- a/test/Parser/cxx0x-member-initializers.cpp
+++ b/test/Parser/cxx0x-member-initializers.cpp
@@ -27,3 +27,13 @@ struct V1 {
   int a, b;
   V1() : a(), b{} {}
 };
+
+template <typename, typename> struct T1 { enum {V};};
+template <int, int> struct T2 { enum {V};};
+struct A {
+  T1<int, int> a1 = T1<int, int>(), *a2 = new T1<int,int>;
+  T2<0,0> b1 = T2<0,0>(), b2 = T2<0,0>(), b3;
+  bool c1 = 1 < 2, c2 = 2 < 1, c3 = false;
+  bool d1 = T1<int, T1<int, int>>::V < 3, d2;
+  T1<int, int()> e = T1<int, int()>();
+};
-- 
1.7.12.1



_______________________________________________
cfe-dev mailing list
cfe-dev@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic