Use RAII objects to ensure proper destruction of expression and statement AST nodes in the parser in most cases, even on error.

llvm-svn: 60057
This commit is contained in:
Sebastian Redl 2008-11-25 22:21:31 +00:00
parent 474003763f
commit 511ed55524
10 changed files with 256 additions and 101 deletions

View File

@ -445,8 +445,9 @@ private:
ExprResult ParseSizeofAlignofExpression();
ExprResult ParseBuiltinPrimaryExpression();
typedef llvm::SmallVector<ExprTy*, 8> ExprListTy;
typedef llvm::SmallVector<SourceLocation, 8> CommaLocsTy;
static const unsigned ExprListSize = 12;
typedef llvm::SmallVector<ExprTy*, ExprListSize> ExprListTy;
typedef llvm::SmallVector<SourceLocation, ExprListSize> CommaLocsTy;
/// ParseExpressionList - Used for C/C++ (argument-)expression-list.
bool ParseExpressionList(ExprListTy &Exprs, CommaLocsTy &CommaLocs);

106
clang/lib/Parse/AstGuard.h Normal file
View File

@ -0,0 +1,106 @@
//===--- AstGuard.h - Parser Ownership Tracking Utilities -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines RAII objects for managing ExprTy* and StmtTy*.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_PARSE_ASTGUARD_H
#define LLVM_CLANG_PARSE_ASTGUARD_H
#include "clang/Parse/Action.h"
#include "llvm/ADT/SmallVector.h"
namespace clang
{
/// RAII guard for freeing StmtTys and ExprTys on early exit in the parser.
/// Instantiated for statements and expressions (Action::DeleteStmt and
/// Action::DeleteExpr).
template <void (Action::*Destroyer)(void*)>
class ASTGuard {
Action &Actions;
void *Node;
void destroy() {
if (Node)
(Actions.*Destroyer)(Node);
}
ASTGuard(const ASTGuard&); // DO NOT IMPLEMENT
// Reference member prevents copy assignment.
public:
explicit ASTGuard(Action &actions) : Actions(actions), Node(0) {}
ASTGuard(Action &actions, void *node)
: Actions(actions), Node(node) {}
template <unsigned N>
ASTGuard(Action &actions, const Action::ActionResult<N> &res)
: Actions(actions), Node(res.Val) {}
~ASTGuard() { destroy(); }
void reset(void *element) {
destroy();
Node = element;
}
template <unsigned N>
void reset(const Action::ActionResult<N> &res) {
reset(res.Val);
}
void *take() {
void *Temp = Node;
Node = 0;
return Temp;
}
void *get() const { return Node; }
};
typedef ASTGuard<&Action::DeleteStmt> StmtGuard;
typedef ASTGuard<&Action::DeleteExpr> ExprGuard;
/// RAII SmallVector wrapper that holds Action::ExprTy* and similar,
/// automatically freeing them on destruction unless it's been disowned.
/// Instantiated for statements and expressions (Action::DeleteStmt and
/// Action::DeleteExpr).
template <void (Action::*Destroyer)(void*), unsigned N>
class ASTVector : public llvm::SmallVector<void*, N> {
private:
Action &Actions;
bool Owns;
void destroy() {
if (Owns) {
while (!this->empty()) {
(Actions.*Destroyer)(this->back());
this->pop_back();
}
}
}
ASTVector(const ASTVector&); // DO NOT IMPLEMENT
// Reference member prevents copy assignment.
public:
ASTVector(Action &actions) : Actions(actions), Owns(true) {}
~ASTVector() { destroy(); }
void **take() {
Owns = false;
return &(*this)[0];
}
};
/// A SmallVector of statements, with stack size 32 (as that is the only one
/// used.)
typedef ASTVector<&Action::DeleteStmt, 32> StmtVector;
/// A SmallVector of expressions, with stack size 12 (the maximum used.)
typedef ASTVector<&Action::DeleteExpr, 12> ExprVector;
}
#endif

View File

@ -15,6 +15,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Parse/Scope.h"
#include "ExtensionRAIIObject.h"
#include "AstGuard.h"
#include "llvm/ADT/SmallSet.h"
using namespace clang;
@ -122,7 +123,7 @@ AttributeList *Parser::ParseAttributes() {
} else if (Tok.is(tok::comma)) {
ConsumeToken();
// __attribute__(( format(printf, 1, 2) ))
llvm::SmallVector<ExprTy*, 8> ArgExprs;
ExprVector ArgExprs(Actions);
bool ArgExprsOk = true;
// now parse the non-empty comma separated list of expressions
@ -142,7 +143,7 @@ AttributeList *Parser::ParseAttributes() {
if (ArgExprsOk && Tok.is(tok::r_paren)) {
ConsumeParen(); // ignore the right paren loc for now
CurrAttr = new AttributeList(AttrName, AttrNameLoc, ParmName,
ParmLoc, &ArgExprs[0], ArgExprs.size(), CurrAttr);
ParmLoc, ArgExprs.take(), ArgExprs.size(), CurrAttr);
}
}
} else { // not an identifier
@ -154,7 +155,7 @@ AttributeList *Parser::ParseAttributes() {
0, SourceLocation(), 0, 0, CurrAttr);
} else {
// __attribute__(( aligned(16) ))
llvm::SmallVector<ExprTy*, 8> ArgExprs;
ExprVector ArgExprs(Actions);
bool ArgExprsOk = true;
// now parse the list of expressions
@ -175,7 +176,7 @@ AttributeList *Parser::ParseAttributes() {
if (ArgExprsOk && Tok.is(tok::r_paren)) {
ConsumeParen(); // ignore the right paren loc for now
CurrAttr = new AttributeList(AttrName, AttrNameLoc, 0,
SourceLocation(), &ArgExprs[0], ArgExprs.size(),
SourceLocation(), ArgExprs.take(), ArgExprs.size(),
CurrAttr);
}
}
@ -295,7 +296,7 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
} else if (Tok.is(tok::l_paren)) {
// Parse C++ direct initializer: '(' expression-list ')'
SourceLocation LParenLoc = ConsumeParen();
ExprListTy Exprs;
ExprVector Exprs(Actions);
CommaLocsTy CommaLocs;
bool InvalidExpr = false;
@ -310,7 +311,7 @@ ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D) {
assert(!Exprs.empty() && Exprs.size()-1 == CommaLocs.size() &&
"Unexpected number of commas!");
Actions.AddCXXDirectInitializerToDecl(LastDeclInGroup, LParenLoc,
&Exprs[0], Exprs.size(),
Exprs.take(), Exprs.size(),
&CommaLocs[0], RParenLoc);
}
} else {
@ -1988,6 +1989,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
} else { // we have an expression.
ExprResult Result = ParseExpression();
ExprGuard ResultGuard(Actions, Result);
if (Result.isInvalid || Tok.isNot(tok::r_paren)) {
MatchRHSPunctuation(tok::r_paren, LParenLoc);
@ -1997,7 +1999,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
const char *PrevSpec = 0;
// Check for duplicate type specifiers (e.g. "int typeof(int)").
if (DS.SetTypeSpecType(DeclSpec::TST_typeofExpr, StartLoc, PrevSpec,
Result.Val))
ResultGuard.take()))
Diag(StartLoc, diag::err_invalid_decl_spec_combination) << PrevSpec;
}
DS.SetRangeEnd(RParenLoc);

View File

@ -15,6 +15,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "AstGuard.h"
using namespace clang;
/// ParseNamespace - We know that the current token is a namespace keyword. This
@ -377,8 +378,8 @@ Parser::BaseResult Parser::ParseBaseSpecifier(DeclTy *ClassDecl)
// Notify semantic analysis that we have parsed a complete
// base-specifier.
return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, BaseType,
BaseLoc);
return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access,
BaseType, BaseLoc);
}
/// getAccessSpecifierIfPresent - Determine whether the next token is
@ -747,7 +748,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclTy *ConstructorDecl) {
SourceLocation LParenLoc = ConsumeParen();
// Parse the optional expression-list.
ExprListTy ArgExprs;
ExprVector ArgExprs(Actions);
CommaLocsTy CommaLocs;
if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) {
SkipUntil(tok::r_paren);
@ -757,8 +758,8 @@ Parser::MemInitResult Parser::ParseMemInitializer(DeclTy *ConstructorDecl) {
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
return Actions.ActOnMemInitializer(ConstructorDecl, CurScope, II, IdLoc,
LParenLoc, &ArgExprs[0], ArgExprs.size(),
&CommaLocs[0], RParenLoc);
LParenLoc, ArgExprs.take(),
ArgExprs.size(), &CommaLocs[0], RParenLoc);
}
/// ParseExceptionSpecification - Parse a C++ exception-specification

View File

@ -23,6 +23,7 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "ExtensionRAIIObject.h"
#include "AstGuard.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@ -238,12 +239,15 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind());
SourceLocation ColonLoc;
ExprGuard LHSGuard(Actions, LHS);
while (1) {
// If this token has a lower precedence than we are allowed to parse (e.g.
// because we are called recursively, or because the token is not a binop),
// then we are done!
if (NextTokPrec < MinPrec)
if (NextTokPrec < MinPrec) {
LHSGuard.take();
return LHS;
}
// Consume the operator, saving the operator token for error reporting.
Token OpToken = Tok;
@ -251,6 +255,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
// Special case handling for the ternary operator.
ExprResult TernaryMiddle(true);
ExprGuard MiddleGuard(Actions);
if (NextTokPrec == prec::Conditional) {
if (Tok.isNot(tok::colon)) {
// Handle this production specially:
@ -259,7 +264,6 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
// 'logical-OR-expression' as we might expect.
TernaryMiddle = ParseExpression();
if (TernaryMiddle.isInvalid) {
Actions.DeleteExpr(LHS.Val);
return TernaryMiddle;
}
} else {
@ -268,12 +272,11 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
TernaryMiddle = ExprResult(false);
Diag(Tok, diag::ext_gnu_conditional_expr);
}
MiddleGuard.reset(TernaryMiddle);
if (Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_colon);
Diag(OpToken, diag::note_matching) << "?";
Actions.DeleteExpr(LHS.Val);
Actions.DeleteExpr(TernaryMiddle.Val);
return ExprResult(true);
}
@ -284,10 +287,9 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
// Parse another leaf here for the RHS of the operator.
ExprResult RHS = ParseCastExpression(false);
if (RHS.isInvalid) {
Actions.DeleteExpr(LHS.Val);
Actions.DeleteExpr(TernaryMiddle.Val);
return RHS;
}
ExprGuard RHSGuard(Actions, RHS);
// Remember the precedence of this operator and get the precedence of the
// operator immediately to the right of the RHS.
@ -306,12 +308,13 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
// more tightly than the current operator. If it is left-associative, it
// is okay, to bind exactly as tightly. For example, compile A=B=C=D as
// A=(B=(C=D)), where each paren is a level of recursion here.
// The function takes ownership of the RHS.
RHSGuard.take();
RHS = ParseRHSOfBinaryExpression(RHS, ThisPrec + !isRightAssoc);
if (RHS.isInvalid) {
Actions.DeleteExpr(LHS.Val);
Actions.DeleteExpr(TernaryMiddle.Val);
return RHS;
}
RHSGuard.reset(RHS);
NextTokPrec = getBinOpPrecedence(Tok.getKind());
}
@ -319,17 +322,18 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) {
if (!LHS.isInvalid) {
// Combine the LHS and RHS into the LHS (e.g. build AST).
LHSGuard.take();
MiddleGuard.take();
RHSGuard.take();
if (TernaryMiddle.isInvalid)
LHS = Actions.ActOnBinOp(CurScope, OpToken.getLocation(),
OpToken.getKind(), LHS.Val, RHS.Val);
else
LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc,
LHS.Val, TernaryMiddle.Val, RHS.Val);
} else {
// We had a semantic error on the LHS. Just free the RHS and continue.
Actions.DeleteExpr(TernaryMiddle.Val);
Actions.DeleteExpr(RHS.Val);
LHSGuard.reset(LHS);
}
// If we had an invalid LHS, Middle and RHS will be freed by the guards here
}
}
@ -676,24 +680,27 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
/// argument-expression-list ',' assignment-expression
///
Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
ExprGuard LHSGuard(Actions, LHS);
// Now that the primary-expression piece of the postfix-expression has been
// parsed, see if there are any postfix-expression pieces here.
SourceLocation Loc;
while (1) {
switch (Tok.getKind()) {
default: // Not a postfix-expression suffix.
LHSGuard.take();
return LHS;
case tok::l_square: { // postfix-expression: p-e '[' expression ']'
Loc = ConsumeBracket();
ExprResult Idx = ParseExpression();
ExprGuard IdxGuard(Actions, Idx);
SourceLocation RLoc = Tok.getLocation();
if (!LHS.isInvalid && !Idx.isInvalid && Tok.is(tok::r_square))
LHS = Actions.ActOnArraySubscriptExpr(CurScope, LHS.Val, Loc,
Idx.Val, RLoc);
else
if (!LHS.isInvalid && !Idx.isInvalid && Tok.is(tok::r_square)) {
LHS = Actions.ActOnArraySubscriptExpr(CurScope, LHSGuard.take(), Loc,
IdxGuard.take(), RLoc);
LHSGuard.reset(LHS);
} else
LHS = ExprResult(true);
// Match the ']'.
@ -702,7 +709,7 @@ Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
}
case tok::l_paren: { // p-e: p-e '(' argument-expression-list[opt] ')'
ExprListTy ArgExprs;
ExprVector ArgExprs(Actions);
CommaLocsTy CommaLocs;
Loc = ConsumeParen();
@ -718,8 +725,10 @@ Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
if (!LHS.isInvalid && Tok.is(tok::r_paren)) {
assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&&
"Unexpected number of commas!");
LHS = Actions.ActOnCallExpr(LHS.Val, Loc, &ArgExprs[0], ArgExprs.size(),
&CommaLocs[0], Tok.getLocation());
LHS = Actions.ActOnCallExpr(LHSGuard.take(), Loc, ArgExprs.take(),
ArgExprs.size(), &CommaLocs[0],
Tok.getLocation());
LHSGuard.reset(LHS);
}
MatchRHSPunctuation(tok::r_paren, Loc);
@ -735,18 +744,22 @@ Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) {
return ExprResult(true);
}
if (!LHS.isInvalid)
LHS = Actions.ActOnMemberReferenceExpr(LHS.Val, OpLoc, OpKind,
if (!LHS.isInvalid) {
LHS = Actions.ActOnMemberReferenceExpr(LHSGuard.take(), OpLoc, OpKind,
Tok.getLocation(),
*Tok.getIdentifierInfo());
LHSGuard.reset(LHS);
}
ConsumeToken();
break;
}
case tok::plusplus: // postfix-expression: postfix-expression '++'
case tok::minusminus: // postfix-expression: postfix-expression '--'
if (!LHS.isInvalid)
if (!LHS.isInvalid) {
LHS = Actions.ActOnPostfixUnaryOp(CurScope, Tok.getLocation(),
Tok.getKind(), LHS.Val);
Tok.getKind(), LHSGuard.take());
LHSGuard.reset(LHS);
}
ConsumeToken();
break;
}
@ -840,6 +853,7 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
default: assert(0 && "Not a builtin primary expression!");
case tok::kw___builtin_va_arg: {
ExprResult Expr = ParseAssignmentExpression();
ExprGuard ExprGuard(Actions, Expr);
if (Expr.isInvalid) {
SkipUntil(tok::r_paren);
return ExprResult(true);
@ -854,7 +868,7 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
Diag(Tok, diag::err_expected_rparen);
return ExprResult(true);
}
Res = Actions.ActOnVAArg(StartLoc, Expr.Val, Ty, ConsumeParen());
Res = Actions.ActOnVAArg(StartLoc, ExprGuard.take(), Ty, ConsumeParen());
break;
}
case tok::kw___builtin_offsetof: {
@ -879,6 +893,7 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
Comps.back().U.IdentInfo = Tok.getIdentifierInfo();
Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken();
// FIXME: This loop leaks the index expressions on error.
while (1) {
if (Tok.is(tok::period)) {
// offsetof-member-designator: offsetof-member-designator '.' identifier
@ -921,6 +936,7 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
}
case tok::kw___builtin_choose_expr: {
ExprResult Cond = ParseAssignmentExpression();
ExprGuard CondGuard(Actions, Cond);
if (Cond.isInvalid) {
SkipUntil(tok::r_paren);
return Cond;
@ -929,6 +945,7 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
return ExprResult(true);
ExprResult Expr1 = ParseAssignmentExpression();
ExprGuard Guard1(Actions, Expr1);
if (Expr1.isInvalid) {
SkipUntil(tok::r_paren);
return Expr1;
@ -937,6 +954,7 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
return ExprResult(true);
ExprResult Expr2 = ParseAssignmentExpression();
ExprGuard Guard2(Actions, Expr2);
if (Expr2.isInvalid) {
SkipUntil(tok::r_paren);
return Expr2;
@ -945,12 +963,12 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
Diag(Tok, diag::err_expected_rparen);
return ExprResult(true);
}
Res = Actions.ActOnChooseExpr(StartLoc, Cond.Val, Expr1.Val, Expr2.Val,
ConsumeParen());
Res = Actions.ActOnChooseExpr(StartLoc, CondGuard.take(), Guard1.take(),
Guard2.take(), ConsumeParen());
break;
}
case tok::kw___builtin_overload: {
llvm::SmallVector<ExprTy*, 8> ArgExprs;
ExprVector ArgExprs(Actions);
llvm::SmallVector<SourceLocation, 8> CommaLocs;
// For each iteration through the loop look for assign-expr followed by a
@ -977,7 +995,7 @@ Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() {
SkipUntil(tok::r_paren);
return ExprResult(true);
}
Res = Actions.ActOnOverloadExpr(&ArgExprs[0], ArgExprs.size(),
Res = Actions.ActOnOverloadExpr(ArgExprs.take(), ArgExprs.size(),
&CommaLocs[0], StartLoc, ConsumeParen());
break;
}

View File

@ -14,6 +14,7 @@
#include "clang/Basic/Diagnostic.h"
#include "clang/Parse/Parser.h"
#include "clang/Parse/DeclSpec.h"
#include "AstGuard.h"
using namespace clang;
/// ParseCXXScopeSpecifier - Parse global scope or nested-name-specifier.
@ -328,7 +329,7 @@ Parser::ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
assert(Tok.is(tok::l_paren) && "Expected '('!");
SourceLocation LParenLoc = ConsumeParen();
ExprListTy Exprs;
ExprVector Exprs(Actions);
CommaLocsTy CommaLocs;
if (Tok.isNot(tok::r_paren)) {
@ -345,7 +346,7 @@ Parser::ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
"Unexpected number of commas!");
return Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep,
LParenLoc,
&Exprs[0], Exprs.size(),
Exprs.take(), Exprs.size(),
&CommaLocs[0], RParenLoc);
}
@ -659,7 +660,7 @@ Parser::ExprResult Parser::ParseCXXNewExpression()
// A '(' now can be a new-placement or the '(' wrapping the type-id in the
// second form of new-expression. It can't be a new-type-id.
ExprListTy PlacementArgs;
ExprVector PlacementArgs(Actions);
SourceLocation PlacementLParen, PlacementRParen;
TypeTy *Ty = 0;
@ -706,7 +707,7 @@ Parser::ExprResult Parser::ParseCXXNewExpression()
ParenTypeId = false;
}
ExprListTy ConstructorArgs;
ExprVector ConstructorArgs(Actions);
SourceLocation ConstructorLParen, ConstructorRParen;
if (Tok.is(tok::l_paren)) {
@ -722,9 +723,9 @@ Parser::ExprResult Parser::ParseCXXNewExpression()
}
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
&PlacementArgs[0], PlacementArgs.size(),
PlacementArgs.take(), PlacementArgs.size(),
PlacementRParen, ParenTypeId, TyStart, Ty, TyEnd,
ConstructorLParen, &ConstructorArgs[0],
ConstructorLParen, ConstructorArgs.take(),
ConstructorArgs.size(), ConstructorRParen);
}

View File

@ -13,6 +13,7 @@
#include "clang/Parse/Designator.h"
#include "clang/Parse/Parser.h"
#include "AstGuard.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallString.h"
using namespace clang;
@ -241,7 +242,7 @@ Parser::ExprResult Parser::ParseBraceInitializer() {
/// InitExprs - This is the actual list of expressions contained in the
/// initializer.
llvm::SmallVector<ExprTy*, 8> InitExprs;
ExprVector InitExprs(Actions);
/// ExprDesignators - For each initializer, keep track of the designator that
/// was specified for it, if any.
@ -289,6 +290,9 @@ Parser::ExprResult Parser::ParseBraceInitializer() {
// parsing the rest of the initializer. This allows us to emit
// diagnostics for later elements that we find. If we don't see a comma,
// assume there is a parse error, and just skip to recover.
// FIXME: This comment doesn't sound right. If there is a r_brace
// immediately, it can't be an error, since there is no other way of
// leaving this loop except through this if.
if (Tok.isNot(tok::comma)) {
SkipUntil(tok::r_brace, false, true);
break;
@ -305,13 +309,9 @@ Parser::ExprResult Parser::ParseBraceInitializer() {
if (Tok.is(tok::r_brace)) break;
}
if (InitExprsOk && Tok.is(tok::r_brace))
return Actions.ActOnInitList(LBraceLoc, &InitExprs[0], InitExprs.size(),
return Actions.ActOnInitList(LBraceLoc, InitExprs.take(), InitExprs.size(),
InitExprDesignations, ConsumeBrace());
// On error, delete any parsed subexpressions.
for (unsigned i = 0, e = InitExprs.size(); i != e; ++i)
Actions.DeleteExpr(InitExprs[i]);
// Match the '}'.
MatchRHSPunctuation(tok::r_brace, LBraceLoc);
return ExprResult(true); // an error occurred.

View File

@ -14,6 +14,7 @@
#include "clang/Parse/Parser.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Parse/Scope.h"
#include "AstGuard.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
@ -1194,6 +1195,7 @@ Parser::StmtResult Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
}
ConsumeParen(); // '('
ExprResult Res = ParseExpression();
ExprGuard ResGuard(Actions, Res);
if (Res.isInvalid) {
SkipUntil(tok::semi);
return true;
@ -1216,7 +1218,8 @@ Parser::StmtResult Parser::ParseObjCSynchronizedStmt(SourceLocation atLoc) {
ExitScope();
if (SynchBody.isInvalid)
SynchBody = Actions.ActOnNullStmt(Tok.getLocation());
return Actions.ActOnObjCAtSynchronizedStmt(atLoc, Res.Val, SynchBody.Val);
return Actions.ActOnObjCAtSynchronizedStmt(atLoc, ResGuard.take(),
SynchBody.Val);
}
/// objc-try-catch-statement:
@ -1245,6 +1248,8 @@ Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
ExitScope();
if (TryBody.isInvalid)
TryBody = Actions.ActOnNullStmt(Tok.getLocation());
ExprGuard TryGuard(Actions, TryBody);
ExprGuard CatchGuard(Actions), FinallyGuard(Actions);
while (Tok.is(tok::at)) {
// At this point, we need to lookahead to determine if this @ is the start
@ -1290,7 +1295,8 @@ Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
if (CatchBody.isInvalid)
CatchBody = Actions.ActOnNullStmt(Tok.getLocation());
CatchStmts = Actions.ActOnObjCAtCatchStmt(AtCatchFinallyLoc, RParenLoc,
FirstPart, CatchBody.Val, CatchStmts.Val);
FirstPart, CatchBody.Val, CatchGuard.take());
CatchGuard.reset(CatchStmts);
ExitScope();
} else {
Diag(AtCatchFinallyLoc, diag::err_expected_lparen_after)
@ -1313,6 +1319,7 @@ Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
FinallyBody = Actions.ActOnNullStmt(Tok.getLocation());
FinallyStmt = Actions.ActOnObjCAtFinallyStmt(AtCatchFinallyLoc,
FinallyBody.Val);
FinallyGuard.reset(FinallyStmt);
catch_or_finally_seen = true;
ExitScope();
break;
@ -1322,8 +1329,8 @@ Parser::StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) {
Diag(atLoc, diag::err_missing_catch_finally);
return true;
}
return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.Val, CatchStmts.Val,
FinallyStmt.Val);
return Actions.ActOnObjCAtTryStmt(atLoc, TryGuard.take(), CatchGuard.take(),
FinallyGuard.take());
}
/// objc-method-def: objc-method-proto ';'[opt] '{' body '}'
@ -1468,7 +1475,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
IdentifierInfo *selIdent = ParseObjCSelector(Loc);
llvm::SmallVector<IdentifierInfo *, 12> KeyIdents;
llvm::SmallVector<Action::ExprTy *, 12> KeyExprs;
ExprVector KeyExprs(Actions);
if (Tok.is(tok::colon)) {
while (1) {
@ -1551,9 +1558,9 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc,
return Actions.ActOnClassMessage(CurScope,
ReceiverName, Sel,
LBracLoc, NameLoc, RBracLoc,
&KeyExprs[0], KeyExprs.size());
KeyExprs.take(), KeyExprs.size());
return Actions.ActOnInstanceMessage(ReceiverExpr, Sel, LBracLoc, RBracLoc,
&KeyExprs[0], KeyExprs.size());
KeyExprs.take(), KeyExprs.size());
}
Parser::ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
@ -1564,31 +1571,26 @@ Parser::ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) {
// expressions. At this point, we know that the only valid thing that starts
// with '@' is an @"".
llvm::SmallVector<SourceLocation, 4> AtLocs;
llvm::SmallVector<ExprTy*, 4> AtStrings;
ExprVector AtStrings(Actions);
AtLocs.push_back(AtLoc);
AtStrings.push_back(Res.Val);
while (Tok.is(tok::at)) {
AtLocs.push_back(ConsumeToken()); // eat the @.
ExprResult Res(true); // Invalid unless there is a string literal.
ExprResult Lit(true); // Invalid unless there is a string literal.
if (isTokenStringLiteral())
Res = ParseStringLiteralExpression();
Lit = ParseStringLiteralExpression();
else
Diag(Tok, diag::err_objc_concat_string);
if (Res.isInvalid) {
while (!AtStrings.empty()) {
Actions.DeleteExpr(AtStrings.back());
AtStrings.pop_back();
}
return Res;
}
if (Lit.isInvalid)
return Lit;
AtStrings.push_back(Res.Val);
AtStrings.push_back(Lit.Val);
}
return Actions.ParseObjCStringLiteral(&AtLocs[0], &AtStrings[0],
return Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.take(),
AtStrings.size());
}
@ -1614,7 +1616,6 @@ Parser::ExprResult Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) {
/// objc-protocol-expression
/// @protocol ( protocol-name )
Parser::ExprResult Parser::ParseObjCProtocolExpression(SourceLocation AtLoc) {
SourceLocation ProtoLoc = ConsumeToken();

View File

@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "ParsePragma.h"
#include "AstGuard.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Action.h"
@ -35,12 +36,14 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
Action::PragmaPackKind Kind = Action::PPK_Default;
IdentifierInfo *Name = 0;
Action::ExprResult Alignment;
ExprGuard AlignmentGuard(Actions);
SourceLocation LParenLoc = Tok.getLocation();
PP.Lex(Tok);
if (Tok.is(tok::numeric_constant)) {
Alignment = Actions.ActOnNumericConstant(Tok);
if (Alignment.isInvalid)
return;
AlignmentGuard.reset(Alignment);
PP.Lex(Tok);
} else if (Tok.is(tok::identifier)) {
@ -66,6 +69,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
Alignment = Actions.ActOnNumericConstant(Tok);
if (Alignment.isInvalid)
return;
AlignmentGuard.reset(Alignment);
PP.Lex(Tok);
} else if (Tok.is(tok::identifier)) {
@ -83,6 +87,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
Alignment = Actions.ActOnNumericConstant(Tok);
if (Alignment.isInvalid)
return;
AlignmentGuard.reset(Alignment);
PP.Lex(Tok);
}
@ -100,7 +105,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Token &PackTok) {
}
SourceLocation RParenLoc = Tok.getLocation();
Actions.ActOnPragmaPack(Kind, Name, Alignment.Val, PackLoc,
Actions.ActOnPragmaPack(Kind, Name, AlignmentGuard.take(), PackLoc,
LParenLoc, RParenLoc);
}

View File

@ -14,6 +14,7 @@
#include "clang/Parse/Parser.h"
#include "ExtensionRAIIObject.h"
#include "AstGuard.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Parse/DeclSpec.h"
@ -229,6 +230,7 @@ Parser::StmtResult Parser::ParseCaseStatement() {
SkipUntil(tok::colon);
return true;
}
ExprGuard LHSGuard(Actions, LHS);
// GNU case range extension.
SourceLocation DotDotDotLoc;
@ -244,6 +246,7 @@ Parser::StmtResult Parser::ParseCaseStatement() {
}
RHSVal = RHS.Val;
}
ExprGuard RHSGuard(Actions, RHSVal);
if (Tok.isNot(tok::colon)) {
Diag(Tok, diag::err_expected_colon_after) << "'case'";
@ -265,8 +268,8 @@ Parser::StmtResult Parser::ParseCaseStatement() {
if (SubStmt.isInvalid)
SubStmt = Actions.ActOnNullStmt(ColonLoc);
return Actions.ActOnCaseStmt(CaseLoc, LHS.Val, DotDotDotLoc, RHSVal, ColonLoc,
SubStmt.Val);
return Actions.ActOnCaseStmt(CaseLoc, LHSGuard.take(), DotDotDotLoc,
RHSGuard.take(), ColonLoc, SubStmt.Val);
}
/// ParseDefaultStatement
@ -352,7 +355,8 @@ Parser::StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
// TODO: "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are
// only allowed at the start of a compound stmt regardless of the language.
llvm::SmallVector<StmtTy*, 32> Stmts;
typedef StmtVector StmtsTy;
StmtsTy Stmts(Actions);
while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) {
StmtResult R;
if (Tok.isNot(tok::kw___extension__)) {
@ -410,7 +414,7 @@ Parser::StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) {
SourceLocation RBraceLoc = ConsumeBrace();
return Actions.ActOnCompoundStmt(LBraceLoc, RBraceLoc,
&Stmts[0], Stmts.size(), isStmtExpr);
Stmts.take(), Stmts.size(), isStmtExpr);
}
/// ParseIfStatement
@ -456,6 +460,7 @@ Parser::StmtResult Parser::ParseIfStatement() {
} else {
CondExp = ParseSimpleParenExpression();
}
ExprGuard CondGuard(Actions, CondExp);
if (CondExp.isInvalid) {
SkipUntil(tok::semi);
@ -528,9 +533,7 @@ Parser::StmtResult Parser::ParseIfStatement() {
if ((ThenStmt.isInvalid && ElseStmt.isInvalid) ||
(ThenStmt.isInvalid && ElseStmt.Val == 0) ||
(ThenStmt.Val == 0 && ElseStmt.isInvalid)) {
// Both invalid, or one is invalid and other is non-present: delete cond and
// return error.
Actions.DeleteExpr(CondExp.Val);
// Both invalid, or one is invalid and other is non-present: return error.
return true;
}
@ -540,7 +543,7 @@ Parser::StmtResult Parser::ParseIfStatement() {
if (ElseStmt.isInvalid)
ElseStmt = Actions.ActOnNullStmt(ElseStmtLoc);
return Actions.ActOnIfStmt(IfLoc, CondExp.Val, ThenStmt.Val,
return Actions.ActOnIfStmt(IfLoc, CondGuard.take(), ThenStmt.Val,
ElseLoc, ElseStmt.Val);
}
@ -668,6 +671,7 @@ Parser::StmtResult Parser::ParseWhileStatement() {
} else {
Cond = ParseSimpleParenExpression();
}
ExprGuard CondGuard(Actions, Cond);
// C99 6.8.5p5 - In C99, the body of the if statement is a scope, even if
// there is no compound stmt. C90 does not have this clause. We only do this
@ -685,6 +689,7 @@ Parser::StmtResult Parser::ParseWhileStatement() {
// Read the body statement.
StmtResult Body = ParseStatement();
StmtGuard BodyGuard(Actions, Body);
// Pop the body scope if needed.
if (NeedsInnerScope) ExitScope();
@ -693,7 +698,7 @@ Parser::StmtResult Parser::ParseWhileStatement() {
if (Cond.isInvalid || Body.isInvalid) return true;
return Actions.ActOnWhileStmt(WhileLoc, Cond.Val, Body.Val);
return Actions.ActOnWhileStmt(WhileLoc, CondGuard.take(), BodyGuard.take());
}
/// ParseDoStatement
@ -725,6 +730,7 @@ Parser::StmtResult Parser::ParseDoStatement() {
// Read the body statement.
StmtResult Body = ParseStatement();
StmtGuard BodyGuard(Actions, Body);
// Pop the body scope if needed.
if (NeedsInnerScope) ExitScope();
@ -749,12 +755,14 @@ Parser::StmtResult Parser::ParseDoStatement() {
// Parse the condition.
ExprResult Cond = ParseSimpleParenExpression();
ExprGuard CondGuard(Actions, Cond);
ExitScope();
if (Cond.isInvalid || Body.isInvalid) return true;
return Actions.ActOnDoStmt(DoLoc, Body.Val, WhileLoc, Cond.Val);
return Actions.ActOnDoStmt(DoLoc, BodyGuard.take(),
WhileLoc, CondGuard.take());
}
/// ParseForStatement
@ -810,6 +818,8 @@ Parser::StmtResult Parser::ParseForStatement() {
ExprTy *SecondPart = 0;
StmtTy *ThirdPart = 0;
bool ForEach = false;
StmtGuard FirstGuard(Actions), ThirdGuard(Actions);
ExprGuard SecondGuard(Actions);
// Parse the first part of the for specifier.
if (Tok.is(tok::semi)) { // for (;
@ -856,7 +866,10 @@ Parser::StmtResult Parser::ParseForStatement() {
SkipUntil(tok::semi);
}
}
FirstGuard.reset(FirstPart);
SecondGuard.reset(SecondPart);
if (!ForEach) {
assert(!SecondGuard.get() && "Shouldn't have a second expression yet.");
// Parse the second part of the for specifier.
if (Tok.is(tok::semi)) { // for (...;;
// no second part.
@ -888,6 +901,8 @@ Parser::StmtResult Parser::ParseForStatement() {
ThirdPart = R.Val;
}
}
SecondGuard.reset(SecondPart);
ThirdGuard.reset(ThirdPart);
}
// Match the ')'.
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
@ -918,6 +933,10 @@ Parser::StmtResult Parser::ParseForStatement() {
if (Body.isInvalid)
return Body;
// Release all the guards.
FirstGuard.take();
SecondGuard.take();
ThirdGuard.take();
if (!ForEach)
return Actions.ActOnForStmt(ForLoc, LParenLoc, FirstPart,
SecondPart, ThirdPart, RParenLoc, Body.Val);
@ -1082,11 +1101,12 @@ Parser::StmtResult Parser::ParseAsmStatement(bool &msAsm) {
ExprResult AsmString = ParseAsmStringLiteral();
if (AsmString.isInvalid)
return true;
ExprGuard AsmGuard(Actions, AsmString);
llvm::SmallVector<std::string, 4> Names;
llvm::SmallVector<ExprTy*, 4> Constraints;
llvm::SmallVector<ExprTy*, 4> Exprs;
llvm::SmallVector<ExprTy*, 4> Clobbers;
ExprVector Constraints(Actions);
ExprVector Exprs(Actions);
ExprVector Clobbers(Actions);
unsigned NumInputs = 0, NumOutputs = 0;
@ -1136,9 +1156,9 @@ Parser::StmtResult Parser::ParseAsmStatement(bool &msAsm) {
return Actions.ActOnAsmStmt(AsmLoc, isSimple, isVolatile,
NumOutputs, NumInputs,
&Names[0], &Constraints[0], &Exprs[0],
AsmString.Val,
Clobbers.size(), &Clobbers[0],
&Names[0], Constraints.take(),
Exprs.take(), AsmGuard.take(),
Clobbers.size(), Clobbers.take(),
RParenLoc);
}