[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