forked from qt-creator/qt-creator
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:
51
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
51
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
@@ -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,42 +5494,59 @@ 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
|
||||||
// T_LBRACKET constant-expression T_BRACKET
|
// T_LBRACKET constant-expression T_BRACKET
|
||||||
//
|
//
|
||||||
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
|
||||||
|
1
tests/auto/cplusplus/cxx11/data/lambda.1.cpp
Normal file
1
tests/auto/cplusplus/cxx11/data/lambda.1.cpp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Foo foo([&](int a) { ++a; });
|
@@ -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
|
||||||
//
|
//
|
||||||
|
Reference in New Issue
Block a user