CPlusPlus: fixed parsing function-try-catch with ctor-initializer

C++ standard defines that 'try' should be before optional ctor
initializer, so wrong order changed. Added documentation to
parseTryBlockStatement and new test.

Task-number: QTCREATORBUG-9064
Change-Id: Id19cdc53c034cb1232ae27e0bfe36d85b7ad0452
Reviewed-by: Erik Verbruggen <erik.verbruggen@digia.com>
This commit is contained in:
Sergey Shambir
2013-04-03 23:33:44 +04:00
committed by Erik Verbruggen
parent f7de8c934a
commit 2ead48fb26
3 changed files with 96 additions and 35 deletions

View File

@@ -3066,7 +3066,7 @@ bool Parser::parseStatement(StatementAST *&node)
return parseSwitchStatement(node); return parseSwitchStatement(node);
case T_TRY: case T_TRY:
return parseTryBlockStatement(node); return parseTryBlockStatement(node, 0);
case T_CASE: case T_CASE:
case T_DEFAULT: case T_DEFAULT:
@@ -4027,44 +4027,46 @@ bool Parser::parseSimpleDeclaration(DeclarationAST *&node, ClassSpecifierAST *de
node = ast; node = ast;
return true; return true;
} else if (! _inFunctionBody && declarator && (LA() == T_COLON || LA() == T_LBRACE || LA() == T_TRY)) { } else if (! _inFunctionBody && declarator && (LA() == T_COLON || LA() == T_LBRACE || LA() == T_TRY)) {
CtorInitializerAST *ctor_initializer = 0; if (LA() == T_TRY) {
bool hasCtorInitializer = false; FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST;
if (LA() == T_COLON) { ast->qt_invokable_token = qt_invokable_token;
hasCtorInitializer = true; ast->decl_specifier_list = decl_specifier_seq;
parseCtorInitializer(ctor_initializer); ast->declarator = firstDeclarator;
parseTryBlockStatement(ast->function_body, &ast->ctor_initializer);
node = ast;
return true; // recognized a function definition.
} else {
CtorInitializerAST *ctor_initializer = 0;
bool hasCtorInitializer = false;
if (LA() != T_LBRACE) { if (LA() == T_COLON) {
const unsigned pos = cursor(); hasCtorInitializer = true;
parseCtorInitializer(ctor_initializer);
for (int n = 0; n < 3 && LA(); consumeToken(), ++n)
if (LA() == T_LBRACE)
break;
if (LA() != T_LBRACE) { if (LA() != T_LBRACE) {
error(pos, "unexpected token `%s'", _translationUnit->spell(pos)); const unsigned pos = cursor();
rewind(pos);
for (int n = 0; n < 3 && LA(); consumeToken(), ++n)
if (LA() == T_LBRACE)
break;
if (LA() != T_LBRACE) {
error(pos, "unexpected token `%s'", _translationUnit->spell(pos));
rewind(pos);
}
} }
} }
}
if (LA() == T_LBRACE || hasCtorInitializer) { if (LA() == T_LBRACE || hasCtorInitializer) {
FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST; FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST;
ast->qt_invokable_token = qt_invokable_token; ast->qt_invokable_token = qt_invokable_token;
ast->decl_specifier_list = decl_specifier_seq; ast->decl_specifier_list = decl_specifier_seq;
ast->declarator = firstDeclarator; ast->declarator = firstDeclarator;
ast->ctor_initializer = ctor_initializer; ast->ctor_initializer = ctor_initializer;
parseFunctionBody(ast->function_body); parseFunctionBody(ast->function_body);
node = ast; node = ast;
return true; // recognized a function definition. return true; // recognized a function definition.
} else if (LA() == T_TRY) { }
FunctionDefinitionAST *ast = new (_pool) FunctionDefinitionAST;
ast->qt_invokable_token = qt_invokable_token;
ast->decl_specifier_list = decl_specifier_seq;
ast->declarator = firstDeclarator;
ast->ctor_initializer = ctor_initializer;
parseTryBlockStatement(ast->function_body);
node = ast;
return true; // recognized a function definition.
} }
} }
@@ -4124,13 +4126,50 @@ bool Parser::parseFunctionBody(StatementAST *&node)
return parsed; return parsed;
} }
bool Parser::parseTryBlockStatement(StatementAST *&node) /**
* Parses both try-block and function-try-block
* @param placeholder Non-null for function-try-block in around constructor
*
* try-block:
* try compound-statement handler-seq
* function-try-block:
* try [ctor-initializer] compound-statement handler-seq
*/
bool Parser::parseTryBlockStatement(StatementAST *&node, CtorInitializerAST **placeholder)
{ {
DEBUG_THIS_RULE(); DEBUG_THIS_RULE();
if (LA() == T_TRY) { if (LA() == T_TRY) {
TryBlockStatementAST *ast = new (_pool) TryBlockStatementAST; TryBlockStatementAST *ast = new (_pool) TryBlockStatementAST;
// try
ast->try_token = consumeToken(); ast->try_token = consumeToken();
// [ctor-initializer]
if (LA() == T_COLON) {
const unsigned colonPos = cursor();
CtorInitializerAST *ctor_initializer = 0;
parseCtorInitializer(ctor_initializer);
if (LA() != T_LBRACE) {
const unsigned pos = cursor();
for (int n = 0; n < 3 && LA(); consumeToken(), ++n)
if (LA() == T_LBRACE)
break;
if (LA() != T_LBRACE) {
error(pos, "unexpected token `%s'", _translationUnit->spell(pos));
rewind(pos);
}
}
if (placeholder)
*placeholder = ctor_initializer;
else
error(colonPos, "constructor initializer not allowed inside function body");
}
// compound-statement
parseCompoundStatement(ast->statement); parseCompoundStatement(ast->statement);
// handler-seq
CatchClauseListAST **catch_clause_ptr = &ast->catch_clause_list; CatchClauseListAST **catch_clause_ptr = &ast->catch_clause_list;
while (parseCatchClause(*catch_clause_ptr)) while (parseCatchClause(*catch_clause_ptr))
catch_clause_ptr = &(*catch_clause_ptr)->next; catch_clause_ptr = &(*catch_clause_ptr)->next;

View File

@@ -165,7 +165,7 @@ public:
bool parseTemplateParameter(DeclarationAST *&node); bool parseTemplateParameter(DeclarationAST *&node);
bool parseTemplateParameterList(DeclarationListAST *&node); bool parseTemplateParameterList(DeclarationListAST *&node);
bool parseThrowExpression(ExpressionAST *&node); bool parseThrowExpression(ExpressionAST *&node);
bool parseTryBlockStatement(StatementAST *&node); bool parseTryBlockStatement(StatementAST *&node, CtorInitializerAST **placeholder);
bool parseCatchClause(CatchClauseListAST *&node); bool parseCatchClause(CatchClauseListAST *&node);
bool parseTypeId(ExpressionAST *&node); bool parseTypeId(ExpressionAST *&node);
bool parseTypeIdList(ExpressionListAST *&node); bool parseTypeIdList(ExpressionListAST *&node);

View File

@@ -145,6 +145,7 @@ private slots:
void cpp_constructor_one_named_arg(); void cpp_constructor_one_named_arg();
void cpp_constructor_no_arg(); void cpp_constructor_no_arg();
void cpp_constructor_multiple_args(); void cpp_constructor_multiple_args();
void cpp_constructor_function_try_catch();
// objc++ // objc++
void objc_simple_class(); void objc_simple_class();
@@ -1204,6 +1205,27 @@ void tst_AST::cpp_constructor_multiple_args()
QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0); QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0);
} }
void tst_AST::cpp_constructor_function_try_catch()
{
QSharedPointer<TranslationUnit> unit(parseDeclaration("QFileInfo::QFileInfo(QString name, QString type)"
" try : m_name(name), m_type(type) {}"
" catch (...) {}"));
AST *ast = unit->ast();
QVERIFY(ast != 0);
FunctionDefinitionAST *funDef = ast->asFunctionDefinition();
QVERIFY(funDef != 0);
QVERIFY(funDef->ctor_initializer != 0);
QVERIFY(funDef->declarator != 0);
QVERIFY(funDef->declarator->postfix_declarator_list != 0);
QVERIFY(funDef->declarator->postfix_declarator_list->lastValue() != 0);
FunctionDeclaratorAST *funDecl = funDef->declarator->postfix_declarator_list->lastValue()->asFunctionDeclarator();
QVERIFY(funDecl != 0);
QVERIFY(funDecl->parameter_declaration_clause != 0);
QVERIFY(funDecl->parameter_declaration_clause->parameter_declaration_list != 0);
}
void tst_AST::objc_simple_class() void tst_AST::objc_simple_class()
{ {
QSharedPointer<TranslationUnit> unit(parseDeclaration("\n" QSharedPointer<TranslationUnit> unit(parseDeclaration("\n"