C++: Fix parsing designators vs lambdas

The introduction of C99 designators led to parsing problems with lambdas
that were passed in as a function arguments.

Fixed by prefering to parse without designators first. This will be
cleaner/clearer once the appropriate "LanguageFeatures" from the Project
Parts will be passed in.

Change-Id: Ia9cb7c4a4c9345e729cf2044e1e5411fe63e33ec
Reviewed-by: Wang Hoi <wanghoi@126.com>
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
Nikolai Kosjar
2014-06-17 18:18:54 -04:00
parent d4c62539fd
commit 38b8940bd4
3 changed files with 65 additions and 16 deletions

View File

@@ -2653,10 +2653,13 @@ bool Parser::parseBraceOrEqualInitializer0x(ExpressionAST *&node)
bool Parser::parseInitializerClause0x(ExpressionAST *&node) bool Parser::parseInitializerClause0x(ExpressionAST *&node)
{ {
DEBUG_THIS_RULE();
if (LA() == T_LBRACE) if (LA() == T_LBRACE)
return parseBracedInitList0x(node); return parseBracedInitList0x(node);
return parseAssignmentExpression(node); if (parseAssignmentExpression(node))
return true;
return parseDesignatedInitializer(node);
} }
bool Parser::parseInitializerList0x(ExpressionListAST *&node) bool Parser::parseInitializerList0x(ExpressionListAST *&node)
@@ -2664,7 +2667,7 @@ bool Parser::parseInitializerList0x(ExpressionListAST *&node)
ExpressionListAST **expression_list_ptr = &node; ExpressionListAST **expression_list_ptr = &node;
ExpressionAST *expression = 0; ExpressionAST *expression = 0;
if (parseDesignatedInitializer(expression)) { if (parseInitializerClause0x(expression)) {
*expression_list_ptr = new (_pool) ExpressionListAST; *expression_list_ptr = new (_pool) ExpressionListAST;
(*expression_list_ptr)->value = expression; (*expression_list_ptr)->value = expression;
expression_list_ptr = &(*expression_list_ptr)->next; expression_list_ptr = &(*expression_list_ptr)->next;
@@ -2675,7 +2678,7 @@ bool Parser::parseInitializerList0x(ExpressionListAST *&node)
while (LA() == T_COMMA && LA(2) != T_RBRACE) { while (LA() == T_COMMA && LA(2) != T_RBRACE) {
consumeToken(); // consume T_COMMA consumeToken(); // consume T_COMMA
if (parseDesignatedInitializer(expression)) { if (parseInitializerClause0x(expression)) {
*expression_list_ptr = new (_pool) ExpressionListAST; *expression_list_ptr = new (_pool) ExpressionListAST;
(*expression_list_ptr)->value = expression; (*expression_list_ptr)->value = expression;
@@ -2692,6 +2695,7 @@ bool Parser::parseInitializerList0x(ExpressionListAST *&node)
bool Parser::parseBracedInitList0x(ExpressionAST *&node) bool Parser::parseBracedInitList0x(ExpressionAST *&node)
{ {
DEBUG_THIS_RULE();
if (LA() != T_LBRACE) if (LA() != T_LBRACE)
return false; return false;
@@ -5490,20 +5494,30 @@ bool Parser::parseDesignatedInitializer(ExpressionAST *&node)
{ {
DEBUG_THIS_RULE(); DEBUG_THIS_RULE();
if (!_languageFeatures.c99Enabled || (LA() != T_DOT && LA() != T_LBRACKET)) if (!_languageFeatures.c99Enabled || (LA() != T_DOT && LA() != T_LBRACKET))
return parseInitializerClause0x(node); return false;
DesignatedInitializerAST *ast = new (_pool) DesignatedInitializerAST; DesignatedInitializerAST *ast = new (_pool) DesignatedInitializerAST;
DesignatorListAST **designator_list_ptr = &ast->designator_list; DesignatorListAST **designator_list_ptr = &ast->designator_list;
DesignatorAST *designator = 0; DesignatorAST *designator = 0;
const unsigned start = cursor();
while (parseDesignator(designator)) { while (parseDesignator(designator)) {
*designator_list_ptr = new (_pool) DesignatorListAST; *designator_list_ptr = new (_pool) DesignatorListAST;
(*designator_list_ptr)->value = designator; (*designator_list_ptr)->value = designator;
designator_list_ptr = &(*designator_list_ptr)->next; designator_list_ptr = &(*designator_list_ptr)->next;
} }
match(T_EQUAL, &ast->equal_token); if (start == cursor())
parseInitializerClause0x(ast->initializer); return false;
if (LA() == T_EQUAL) {
ast->equal_token = consumeToken();
if (parseAssignmentExpression(ast->initializer)) {
node = ast; node = ast;
return true; return true;
}
}
rewind(start);
return false;
} }
// designator ::= T_DOT T_IDENTIFIER // designator ::= T_DOT T_IDENTIFIER
@@ -5511,21 +5525,28 @@ bool Parser::parseDesignatedInitializer(ExpressionAST *&node)
// //
bool Parser::parseDesignator(DesignatorAST *&node) bool Parser::parseDesignator(DesignatorAST *&node)
{ {
DesignatorAST *ast = new (_pool) DesignatorAST; DEBUG_THIS_RULE();
const unsigned start = cursor();
if (LA() == T_DOT) { if (LA() == T_DOT) {
DesignatorAST *ast = new (_pool) DesignatorAST;
ast->type = DesignatorAST::Dot; ast->type = DesignatorAST::Dot;
ast->u.dot.dot_token = consumeToken(); ast->u.dot.dot_token = consumeToken();
match(T_IDENTIFIER, &ast->u.dot.identifier_token); match(T_IDENTIFIER, &ast->u.dot.identifier_token);
} else if (LA() == T_LBRACKET) {
ast->type = DesignatorAST::Bracket;
ast->u.bracket.lbracket_token = consumeToken();
parseConstantExpression(ast->u.bracket.expression);
match(T_RBRACKET, &ast->u.bracket.rbracket_token);
} else {
return false;
}
node = ast; node = ast;
return true; return true;
} else if (LA() == T_LBRACKET) {
DesignatorAST *ast = new (_pool) DesignatorAST;
ast->type = DesignatorAST::Bracket;
ast->u.bracket.lbracket_token = consumeToken();
if (parseConditionalExpression(ast->u.bracket.expression)) {
match(T_RBRACKET, &ast->u.bracket.rbracket_token);
node = ast;
return true;
}
}
rewind(start);
return false;
} }
// objc-class-declaraton ::= T_AT_CLASS (T_IDENTIFIER @ T_COMMA) T_SEMICOLON // objc-class-declaraton ::= T_AT_CLASS (T_IDENTIFIER @ T_COMMA) T_SEMICOLON

View File

@@ -0,0 +1 @@
Foo foo([&](int a) { ++a; });

View File

@@ -98,13 +98,14 @@ class tst_cxx11: public QObject
} }
}; };
Document::Ptr document(const QString &fileName, QByteArray *errors = 0) Document::Ptr document(const QString &fileName, QByteArray *errors = 0, bool c99Enabled = false)
{ {
Document::Ptr doc = Document::create(fileName); Document::Ptr doc = Document::create(fileName);
QFile file(testdata(fileName)); QFile file(testdata(fileName));
if (file.open(QFile::ReadOnly)) { if (file.open(QFile::ReadOnly)) {
LanguageFeatures features; LanguageFeatures features;
features.cxx11Enabled = true; features.cxx11Enabled = true;
features.c99Enabled = c99Enabled;
Client client(errors); Client client(errors);
doc->control()->setDiagnosticClient(&client); doc->control()->setDiagnosticClient(&client);
doc->setUtf8Source(QTextStream(&file).readAll().toUtf8()); doc->setUtf8Source(QTextStream(&file).readAll().toUtf8());
@@ -124,6 +125,9 @@ private Q_SLOTS:
void parse_data(); void parse_data();
void parse(); void parse();
void parseWithC99Enabled_data();
void parseWithC99Enabled();
// //
// checks for the semantic // checks for the semantic
// //
@@ -169,6 +173,29 @@ void tst_cxx11::parse()
VERIFY_ERRORS(); VERIFY_ERRORS();
} }
void tst_cxx11::parseWithC99Enabled_data()
{
QTest::addColumn<QString>("file");
QTest::addColumn<QString>("errorFile");
QTest::newRow("lambda.1") << "lambda.1.cpp" << "";
}
void tst_cxx11::parseWithC99Enabled()
{
QFETCH(QString, file);
QFETCH(QString, errorFile);
const bool c99Enabled = true;
QByteArray errors;
Document::Ptr doc = document(file, &errors, c99Enabled);
if (! qgetenv("DEBUG").isNull())
printf("%s\n", errors.constData());
VERIFY_ERRORS();
}
// //
// check the visibility of symbols declared inside inline namespaces // check the visibility of symbols declared inside inline namespaces
// //