Ping ?
In the mean time, i realized there is no need to test for r_paren because
SkipUntil already does it. Hence the slightly modified attached patch.
On Sunday 19 May 2013 11:54:27 Olivier Goffart wrote:
> On Sunday 19 May 2013 11:45:57 Olivier Goffart wrote:
> > Hi,
> >
> > I attached a patch to the bug http://llvm.org/bugs/show_bug.cgi?id=14486
>
> Wrong link. I meant
> http://llvm.org/bugs/show_bug.cgi?id=13657
>
> Sorry for the confusion.
>
> > The problem is that a comma can be both the separation between template
> > parameter, or the separation between function arguments.
> >
> > GCC tries to fully parse the part after the comma to see if it can be the
> > separation between function argument:
> > http://code.woboq.org/gcc/gcc/cp/parser.c.html#23442
> >
> > But I was too lazy to do the same (because the function like
> > TryParseParameterDeclarationClause or TryParseDeclarationSpecifier are not
> > good enough and stop too early.)
> > So Instead I used some heuristics in the existence of a '=' before the
> > possible closing '>' as further argument need to find a comma.
> >
> > I am not 100% sure that this cover all the cases, but i could not find an
> > example that breaks.
>From 72b9a23b3df6db5069779af664ee28d4d2572a6b Mon Sep 17 00:00:00 2001
From: Olivier Goffart <[email protected]>
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-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits