forked from OSchip/llvm-project
Implement function-try-blocks. However, there's a very subtle bug that I can't track down.
llvm-svn: 70155
This commit is contained in:
parent
5bf1a6e986
commit
a7b98a772c
|
@ -554,17 +554,16 @@ public:
|
|||
/// function. The variant that accepts a FunctionDecl pointer will
|
||||
/// set that function declaration to the actual declaration
|
||||
/// containing the body (if there is one).
|
||||
CompoundStmt *getBody(ASTContext &Context,
|
||||
const FunctionDecl *&Definition) const;
|
||||
Stmt *getBody(ASTContext &Context, const FunctionDecl *&Definition) const;
|
||||
|
||||
virtual CompoundStmt *getBody(ASTContext &Context) const {
|
||||
virtual Stmt *getBody(ASTContext &Context) const {
|
||||
const FunctionDecl* Definition;
|
||||
return getBody(Context, Definition);
|
||||
}
|
||||
|
||||
/// \brief If the function has a body that is immediately available,
|
||||
/// return it.
|
||||
CompoundStmt *getBodyIfAvailable() const;
|
||||
Stmt *getBodyIfAvailable() const;
|
||||
|
||||
/// isThisDeclarationADefinition - Returns whether this specific
|
||||
/// declaration of the function is also a definition. This does not
|
||||
|
@ -574,7 +573,7 @@ public:
|
|||
/// CodeGenModule.cpp uses it, and I don't know if this would break it.
|
||||
bool isThisDeclarationADefinition() const { return Body; }
|
||||
|
||||
void setBody(CompoundStmt *B) { Body = (Stmt*) B; }
|
||||
void setBody(Stmt *B) { Body = B; }
|
||||
void setLazyBody(uint64_t Offset) { Body = Offset; }
|
||||
|
||||
/// Whether this function is virtual, either by explicit marking, or by
|
||||
|
@ -1148,7 +1147,7 @@ public:
|
|||
SourceLocation getCaretLocation() const { return getLocation(); }
|
||||
|
||||
CompoundStmt *getBody() const { return (CompoundStmt*) Body; }
|
||||
CompoundStmt *getBody(ASTContext &C) const { return (CompoundStmt*) Body; }
|
||||
Stmt *getBody(ASTContext &C) const { return (Stmt*) Body; }
|
||||
void setBody(CompoundStmt *B) { Body = (Stmt*) B; }
|
||||
|
||||
// Iterator access to formal parameters.
|
||||
|
|
|
@ -281,11 +281,18 @@ public:
|
|||
// be defined inside or outside a function etc).
|
||||
bool isDefinedOutsideFunctionOrMethod() const;
|
||||
|
||||
// getBody - If this Decl represents a declaration for a body of code,
|
||||
// such as a function or method definition, this method returns the top-level
|
||||
// Stmt* of that body. Otherwise this method returns null.
|
||||
virtual CompoundStmt* getBody(ASTContext &Context) const { return 0; }
|
||||
|
||||
/// getBody - If this Decl represents a declaration for a body of code,
|
||||
/// such as a function or method definition, this method returns the
|
||||
/// top-level Stmt* of that body. Otherwise this method returns null.
|
||||
virtual Stmt* getBody(ASTContext &Context) const { return 0; }
|
||||
|
||||
/// getCompoundBody - Returns getBody(), dyn_casted to a CompoundStmt.
|
||||
CompoundStmt* getCompoundBody(ASTContext &Context) const;
|
||||
|
||||
/// getBodyRBrace - Gets the right brace of the body, if a body exists.
|
||||
/// This works whether the body is a CompoundStmt or a CXXTryStmt.
|
||||
SourceLocation getBodyRBrace(ASTContext &Context) const;
|
||||
|
||||
// global temp stats (until we have a per-module visitor)
|
||||
static void addDeclKind(Kind k);
|
||||
static bool CollectingStats(bool Enable = false);
|
||||
|
|
|
@ -242,11 +242,11 @@ public:
|
|||
return ImplementationControl(DeclImplementation);
|
||||
}
|
||||
|
||||
virtual CompoundStmt *getBody(ASTContext &C) const {
|
||||
return (CompoundStmt*) Body;
|
||||
virtual Stmt *getBody(ASTContext &C) const {
|
||||
return (Stmt*) Body;
|
||||
}
|
||||
CompoundStmt *getBody() { return (CompoundStmt*)Body; }
|
||||
void setBody(CompoundStmt *B) { Body = (Stmt*) B; }
|
||||
void setBody(Stmt *B) { Body = B; }
|
||||
|
||||
// Implement isa/cast/dyncast/etc.
|
||||
static bool classof(const Decl *D) { return D->getKind() == ObjCMethod; }
|
||||
|
|
|
@ -205,6 +205,7 @@ def err_expected_member_or_base_name : Error<
|
|||
def ext_ellipsis_exception_spec : Extension<
|
||||
"exception specification of '...' is a Microsoft extension">;
|
||||
def err_expected_catch : Error<"expected catch">;
|
||||
def err_expected_lbrace_or_comma : Error<"expected '{' or ','">;
|
||||
|
||||
// C++ derived classes
|
||||
def err_dup_virtual : Error<"duplicate 'virtual' in base specifier">;
|
||||
|
|
|
@ -795,6 +795,7 @@ private:
|
|||
// C++ 6: Statements and Blocks
|
||||
|
||||
OwningStmtResult ParseCXXTryBlock();
|
||||
OwningStmtResult ParseCXXTryBlockCommon(SourceLocation TryLoc);
|
||||
OwningStmtResult ParseCXXCatchBlock();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -815,7 +816,8 @@ private:
|
|||
bool RequireSemi = true);
|
||||
DeclGroupPtrTy ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D);
|
||||
DeclPtrTy ParseFunctionStatementBody(DeclPtrTy Decl);
|
||||
|
||||
DeclPtrTy ParseFunctionTryBlock(DeclPtrTy Decl);
|
||||
|
||||
bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS,
|
||||
TemplateParameterLists *TemplateParams,
|
||||
AccessSpecifier AS);
|
||||
|
|
|
@ -321,22 +321,22 @@ void FunctionDecl::Destroy(ASTContext& C) {
|
|||
}
|
||||
|
||||
|
||||
CompoundStmt *FunctionDecl::getBody(ASTContext &Context,
|
||||
const FunctionDecl *&Definition) const {
|
||||
Stmt *FunctionDecl::getBody(ASTContext &Context,
|
||||
const FunctionDecl *&Definition) const {
|
||||
for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) {
|
||||
if (FD->Body) {
|
||||
Definition = FD;
|
||||
return cast<CompoundStmt>(FD->Body.get(Context.getExternalSource()));
|
||||
return FD->Body.get(Context.getExternalSource());
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CompoundStmt *FunctionDecl::getBodyIfAvailable() const {
|
||||
Stmt *FunctionDecl::getBodyIfAvailable() const {
|
||||
for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) {
|
||||
if (FD->Body && !FD->Body.isOffset()) {
|
||||
return cast<CompoundStmt>(FD->Body.get(0));
|
||||
return FD->Body.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include "clang/AST/ExternalASTSource.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
|
@ -341,6 +343,21 @@ DeclContext *Decl::castToDeclContext(const Decl *D) {
|
|||
}
|
||||
}
|
||||
|
||||
CompoundStmt* Decl::getCompoundBody(ASTContext &Context) const {
|
||||
return dyn_cast_or_null<CompoundStmt>(getBody(Context));
|
||||
}
|
||||
|
||||
SourceLocation Decl::getBodyRBrace(ASTContext &Context) const {
|
||||
Stmt *Body = getBody(Context);
|
||||
if (!Body)
|
||||
return SourceLocation();
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Body))
|
||||
return CS->getRBracLoc();
|
||||
assert(isa<CXXTryStmt>(Body) &&
|
||||
"Body can only be CompoundStmt or CXXTryStmt");
|
||||
return cast<CXXTryStmt>(Body)->getSourceRange().getEnd();
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void Decl::CheckAccessDeclContext() const {
|
||||
assert((Access != AS_none || isa<TranslationUnitDecl>(this) ||
|
||||
|
|
|
@ -189,7 +189,7 @@ PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode<GRState>* N) {
|
|||
if (Stmt *S = GetNextStmt(N))
|
||||
return PathDiagnosticLocation(S, SMgr);
|
||||
|
||||
return FullSourceLoc(CodeDecl.getBody(getContext())->getRBracLoc(), SMgr);
|
||||
return FullSourceLoc(CodeDecl.getBodyRBrace(getContext()), SMgr);
|
||||
}
|
||||
|
||||
PathDiagnosticLocation
|
||||
|
@ -825,7 +825,9 @@ public:
|
|||
|
||||
// Finally, add an initial edge from the start location of the first
|
||||
// statement (if it doesn't already exist).
|
||||
if (const CompoundStmt *CS = PDB.getCodeDecl().getBody(PDB.getContext()))
|
||||
// FIXME: Should handle CXXTryStmt if analyser starts supporting C++.
|
||||
if (const CompoundStmt *CS =
|
||||
PDB.getCodeDecl().getCompoundBody(PDB.getContext()))
|
||||
if (!CS->body_empty()) {
|
||||
SourceLocation Loc = (*CS->body_begin())->getLocStart();
|
||||
rawAddEdge(PathDiagnosticLocation(Loc, PDB.getSourceManager()));
|
||||
|
|
|
@ -3047,11 +3047,11 @@ CFRefLeakReport::getEndPath(BugReporter& br, const ExplodedNode<GRState>* EndN){
|
|||
|
||||
LeakN = LeakN->succ_empty() ? 0 : *(LeakN->succ_begin());
|
||||
}
|
||||
|
||||
|
||||
if (!L.isValid()) {
|
||||
CompoundStmt *CS
|
||||
= BR.getStateManager().getCodeDecl().getBody(BR.getContext());
|
||||
L = PathDiagnosticLocation(CS->getRBracLoc(), SMgr);
|
||||
L = PathDiagnosticLocation(
|
||||
BR.getStateManager().getCodeDecl().getBodyRBrace(BR.getContext()),
|
||||
SMgr);
|
||||
}
|
||||
|
||||
std::string sbuf;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include <sstream>
|
||||
|
@ -197,8 +198,12 @@ PathDiagnosticRange PathDiagnosticLocation::asRange() const {
|
|||
// FIXME: We would like to always get the function body, even
|
||||
// when it needs to be de-serialized, but getting the
|
||||
// ASTContext here requires significant changes.
|
||||
if (CompoundStmt *Body = FD->getBodyIfAvailable())
|
||||
return Body->getSourceRange();
|
||||
if (Stmt *Body = FD->getBodyIfAvailable()) {
|
||||
if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Body))
|
||||
return CS->getSourceRange();
|
||||
else
|
||||
return cast<CXXTryStmt>(Body)->getSourceRange();
|
||||
}
|
||||
}
|
||||
else {
|
||||
SourceLocation L = D->getLocation();
|
||||
|
|
|
@ -129,7 +129,7 @@ void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) {
|
|||
DebugInfo = CGM.getDebugInfo();
|
||||
StartObjCMethod(OMD, OMD->getClassInterface());
|
||||
EmitStmt(OMD->getBody(getContext()));
|
||||
FinishFunction(cast<CompoundStmt>(OMD->getBody(getContext()))->getRBracLoc());
|
||||
FinishFunction(OMD->getBodyRBrace(getContext()));
|
||||
}
|
||||
|
||||
// FIXME: I wasn't sure about the synthesis approach. If we end up
|
||||
|
|
|
@ -225,12 +225,13 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD,
|
|||
FProto->getArgType(i)));
|
||||
}
|
||||
|
||||
const CompoundStmt *S = FD->getBody(getContext());
|
||||
// FIXME: Support CXXTryStmt here, too.
|
||||
if (const CompoundStmt *S = FD->getCompoundBody(getContext())) {
|
||||
StartFunction(FD, FD->getResultType(), Fn, Args, S->getLBracLoc());
|
||||
EmitStmt(S);
|
||||
FinishFunction(S->getRBracLoc());
|
||||
}
|
||||
|
||||
StartFunction(FD, FD->getResultType(), Fn, Args, S->getLBracLoc());
|
||||
EmitStmt(S);
|
||||
FinishFunction(S->getRBracLoc());
|
||||
|
||||
// Destroy the 'this' declaration.
|
||||
if (CXXThisDecl)
|
||||
CXXThisDecl->Destroy(getContext());
|
||||
|
|
|
@ -17,15 +17,15 @@
|
|||
#include "clang/Parse/Scope.h"
|
||||
using namespace clang;
|
||||
|
||||
/// ParseInlineCXXMethodDef - We parsed and verified that the specified
|
||||
/// ParseCXXInlineMethodDef - We parsed and verified that the specified
|
||||
/// Declarator is a well formed C++ inline method definition. Now lex its body
|
||||
/// and store its tokens for parsing after the C++ class is complete.
|
||||
Parser::DeclPtrTy
|
||||
Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
|
||||
assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
|
||||
"This isn't a function declarator!");
|
||||
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon)) &&
|
||||
"Current token not a '{' or ':'!");
|
||||
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) &&
|
||||
"Current token not a '{', ':' or 'try'!");
|
||||
|
||||
DeclPtrTy FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0);
|
||||
|
||||
|
@ -34,8 +34,9 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
|
|||
getCurTopClassStack().MethodDefs.push_back(LexedMethod(FnD));
|
||||
CachedTokens &Toks = getCurTopClassStack().MethodDefs.back().Toks;
|
||||
|
||||
// We may have a constructor initializer here.
|
||||
if (Tok.is(tok::colon)) {
|
||||
tok::TokenKind kind = Tok.getKind();
|
||||
// We may have a constructor initializer or function-try-block here.
|
||||
if (kind == tok::colon || kind == tok::kw_try) {
|
||||
// Consume everything up to (and including) the left brace.
|
||||
if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) {
|
||||
// We didn't find the left-brace we expected after the
|
||||
|
@ -58,6 +59,14 @@ Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) {
|
|||
// Consume everything up to (and including) the matching right brace.
|
||||
ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
|
||||
|
||||
// If we're in a function-try-block, we need to store all the catch blocks.
|
||||
if (kind == tok::kw_try) {
|
||||
while (Tok.is(tok::kw_catch)) {
|
||||
ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks);
|
||||
ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
|
||||
}
|
||||
}
|
||||
|
||||
return FnD;
|
||||
}
|
||||
|
||||
|
@ -126,14 +135,18 @@ void Parser::ParseLexedMethodDefs() {
|
|||
|
||||
// Consume the previously pushed token.
|
||||
ConsumeAnyToken();
|
||||
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon)) &&
|
||||
"Inline method not starting with '{' or ':'");
|
||||
assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
|
||||
&& "Inline method not starting with '{', ':' or 'try'");
|
||||
|
||||
// Parse the method body. Function body parsing code is similar enough
|
||||
// to be re-used for method bodies as well.
|
||||
ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
|
||||
Actions.ActOnStartOfFunctionDef(CurScope, LM.D);
|
||||
|
||||
if (Tok.is(tok::kw_try)) {
|
||||
ParseFunctionTryBlock(LM.D);
|
||||
return;
|
||||
}
|
||||
if (Tok.is(tok::colon))
|
||||
ParseConstructorInitializer(LM.D);
|
||||
// FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'??
|
||||
|
|
|
@ -737,7 +737,8 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) {
|
|||
|
||||
// function-definition:
|
||||
if (Tok.is(tok::l_brace)
|
||||
|| (DeclaratorInfo.isFunctionDeclarator() && Tok.is(tok::colon))) {
|
||||
|| (DeclaratorInfo.isFunctionDeclarator() &&
|
||||
(Tok.is(tok::colon) || Tok.is(tok::kw_try)))) {
|
||||
if (!DeclaratorInfo.isFunctionDeclarator()) {
|
||||
Diag(Tok, diag::err_func_def_no_params);
|
||||
ConsumeBrace();
|
||||
|
@ -1044,6 +1045,7 @@ void Parser::ParseConstructorInitializer(DeclPtrTy ConstructorDecl) {
|
|||
break;
|
||||
else {
|
||||
// Skip over garbage, until we get to '{'. Don't eat the '{'.
|
||||
Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma);
|
||||
SkipUntil(tok::l_brace, true, true);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1289,7 +1289,7 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl<std::string> &Names,
|
|||
Parser::DeclPtrTy Parser::ParseFunctionStatementBody(DeclPtrTy Decl) {
|
||||
assert(Tok.is(tok::l_brace));
|
||||
SourceLocation LBraceLoc = Tok.getLocation();
|
||||
|
||||
|
||||
PrettyStackTraceActionsDecl CrashInfo(Decl, LBraceLoc, Actions,
|
||||
PP.getSourceManager(),
|
||||
"parsing function body");
|
||||
|
@ -1307,18 +1307,58 @@ Parser::DeclPtrTy Parser::ParseFunctionStatementBody(DeclPtrTy Decl) {
|
|||
return Actions.ActOnFinishFunctionBody(Decl, move(FnBody));
|
||||
}
|
||||
|
||||
/// ParseFunctionTryBlock - Parse a C++ function-try-block.
|
||||
///
|
||||
/// function-try-block:
|
||||
/// 'try' ctor-initializer[opt] compound-statement handler-seq
|
||||
///
|
||||
Parser::DeclPtrTy Parser::ParseFunctionTryBlock(DeclPtrTy Decl) {
|
||||
assert(Tok.is(tok::kw_try) && "Expected 'try'");
|
||||
SourceLocation TryLoc = ConsumeToken();
|
||||
|
||||
PrettyStackTraceActionsDecl CrashInfo(Decl, TryLoc, Actions,
|
||||
PP.getSourceManager(),
|
||||
"parsing function try block");
|
||||
|
||||
// Constructor initializer list?
|
||||
if (Tok.is(tok::colon))
|
||||
ParseConstructorInitializer(Decl);
|
||||
|
||||
OwningStmtResult FnBody(ParseCXXTryBlockCommon(TryLoc));
|
||||
// If we failed to parse the try-catch, we just give the function an empty
|
||||
// compound statement as the body.
|
||||
if (FnBody.isInvalid())
|
||||
FnBody = Actions.ActOnCompoundStmt(TryLoc, TryLoc,
|
||||
MultiStmtArg(Actions), false);
|
||||
|
||||
return Actions.ActOnFinishFunctionBody(Decl, move(FnBody));
|
||||
}
|
||||
|
||||
/// ParseCXXTryBlock - Parse a C++ try-block.
|
||||
///
|
||||
/// try-block:
|
||||
/// 'try' compound-statement handler-seq
|
||||
///
|
||||
/// handler-seq:
|
||||
/// handler handler-seq[opt]
|
||||
///
|
||||
Parser::OwningStmtResult Parser::ParseCXXTryBlock() {
|
||||
assert(Tok.is(tok::kw_try) && "Expected 'try'");
|
||||
|
||||
SourceLocation TryLoc = ConsumeToken();
|
||||
return ParseCXXTryBlockCommon(TryLoc);
|
||||
}
|
||||
|
||||
/// ParseCXXTryBlockCommon - Parse the common part of try-block and
|
||||
/// function-try-block.
|
||||
///
|
||||
/// try-block:
|
||||
/// 'try' compound-statement handler-seq
|
||||
///
|
||||
/// function-try-block:
|
||||
/// 'try' ctor-initializer[opt] compound-statement handler-seq
|
||||
///
|
||||
/// handler-seq:
|
||||
/// handler handler-seq[opt]
|
||||
///
|
||||
Parser::OwningStmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) {
|
||||
if (Tok.isNot(tok::l_brace))
|
||||
return StmtError(Diag(Tok, diag::err_expected_lbrace));
|
||||
OwningStmtResult TryBlock(ParseCompoundStatement());
|
||||
|
|
|
@ -536,7 +536,8 @@ Parser::ParseDeclarationOrFunctionDefinition(
|
|||
(!getLang().CPlusPlus &&
|
||||
isDeclarationSpecifier()) || // int X(f) int f; {}
|
||||
(getLang().CPlusPlus &&
|
||||
Tok.is(tok::colon)))) { // X() : Base() {} (used for ctors)
|
||||
(Tok.is(tok::colon) || // X() : Base() {} (used for ctors)
|
||||
Tok.is(tok::kw_try))))) { // X() try { ... }
|
||||
if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) {
|
||||
Diag(Tok, diag::err_function_declared_typedef);
|
||||
|
||||
|
@ -575,7 +576,7 @@ Parser::ParseDeclarationOrFunctionDefinition(
|
|||
/// decl-specifier-seq[opt] declarator ctor-initializer[opt]
|
||||
/// function-body
|
||||
/// [C++] function-definition: [C++ 8.4]
|
||||
/// decl-specifier-seq[opt] declarator function-try-block [TODO]
|
||||
/// decl-specifier-seq[opt] declarator function-try-block
|
||||
///
|
||||
Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D) {
|
||||
const DeclaratorChunk &FnTypeInfo = D.getTypeObject(0);
|
||||
|
@ -602,8 +603,8 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D) {
|
|||
|
||||
// We should have either an opening brace or, in a C++ constructor,
|
||||
// we may have a colon.
|
||||
// FIXME: In C++, we might also find the 'try' keyword.
|
||||
if (Tok.isNot(tok::l_brace) && Tok.isNot(tok::colon)) {
|
||||
if (Tok.isNot(tok::l_brace) && Tok.isNot(tok::colon) &&
|
||||
Tok.isNot(tok::kw_try)) {
|
||||
Diag(Tok, diag::err_expected_fn_body);
|
||||
|
||||
// Skip over garbage, until we get to '{'. Don't eat the '{'.
|
||||
|
@ -621,12 +622,14 @@ Parser::DeclPtrTy Parser::ParseFunctionDefinition(Declarator &D) {
|
|||
// specified Declarator for the function.
|
||||
DeclPtrTy Res = Actions.ActOnStartOfFunctionDef(CurScope, D);
|
||||
|
||||
if (Tok.is(tok::kw_try))
|
||||
return ParseFunctionTryBlock(Res);
|
||||
|
||||
// If we have a colon, then we're probably parsing a C++
|
||||
// ctor-initializer.
|
||||
if (Tok.is(tok::colon))
|
||||
ParseConstructorInitializer(Res);
|
||||
|
||||
SourceLocation BraceLoc = Tok.getLocation();
|
||||
return ParseFunctionStatementBody(Res);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/DeclTemplate.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/StmtCXX.h"
|
||||
#include "clang/Parse/DeclSpec.h"
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Basic/SourceManager.h"
|
||||
|
@ -2986,7 +2987,7 @@ Sema::DeclPtrTy Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, DeclPtrTy D) {
|
|||
|
||||
Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg) {
|
||||
Decl *dcl = D.getAs<Decl>();
|
||||
CompoundStmt *Body =cast<CompoundStmt>(static_cast<Stmt*>(BodyArg.release()));
|
||||
Stmt *Body = BodyArg.takeAs<Stmt>();
|
||||
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(dcl)) {
|
||||
FD->setBody(Body);
|
||||
assert(FD == getCurFunctionDecl() && "Function parsing confused");
|
||||
|
@ -3029,13 +3030,16 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg) {
|
|||
// function somewhere so that it is properly owned and so that the goto
|
||||
// has a valid target. Do this by creating a new compound stmt with the
|
||||
// label in it.
|
||||
|
||||
|
||||
// Give the label a sub-statement.
|
||||
L->setSubStmt(new (Context) NullStmt(L->getIdentLoc()));
|
||||
|
||||
std::vector<Stmt*> Elements(Body->body_begin(), Body->body_end());
|
||||
|
||||
CompoundStmt *Compound = isa<CXXTryStmt>(Body) ?
|
||||
cast<CXXTryStmt>(Body)->getTryBlock() :
|
||||
cast<CompoundStmt>(Body);
|
||||
std::vector<Stmt*> Elements(Compound->body_begin(), Compound->body_end());
|
||||
Elements.push_back(L);
|
||||
Body->setStmts(Context, &Elements[0], Elements.size());
|
||||
Compound->setStmts(Context, &Elements[0], Elements.size());
|
||||
}
|
||||
FunctionLabelMap.clear();
|
||||
|
||||
|
|
|
@ -23,3 +23,22 @@ void g()
|
|||
try {}
|
||||
catch {} // expected-error {{expected '('}}
|
||||
}
|
||||
|
||||
void h() try {
|
||||
} catch(...) {
|
||||
}
|
||||
|
||||
struct A {
|
||||
int i;
|
||||
A(float) : i(0) try {} // expected-error {{expected '{' or ','}}
|
||||
A(int);
|
||||
A(char);
|
||||
// FIXME: There's something very strange going on here. After the first
|
||||
// inline function-try-block, subsequent inline bodies aren't parsed anymore.
|
||||
// Valgrind is silent, though, and I can't even debug this properly.
|
||||
A() try : i(0) {} catch(...) {}
|
||||
void f() try {} catch(...) {}
|
||||
};
|
||||
|
||||
A::A(char) : i(0) try {} // expected-error {{expected '{' or ','}}
|
||||
A::A(int j) try : i(j) {} catch(...) {}
|
||||
|
|
|
@ -1091,8 +1091,9 @@ void RewriteBlocks::HandleDeclInMainFile(Decl *D) {
|
|||
// prototype. This enables us to rewrite function declarations and
|
||||
// definitions using the same code.
|
||||
RewriteFunctionProtoType(FD->getType(), FD);
|
||||
|
||||
if (CompoundStmt *Body = FD->getBody(*Context)) {
|
||||
|
||||
// FIXME: Handle CXXTryStmt
|
||||
if (CompoundStmt *Body = FD->getCompoundBody(*Context)) {
|
||||
CurFunctionDef = FD;
|
||||
FD->setBody(cast_or_null<CompoundStmt>(RewriteFunctionBody(Body)));
|
||||
// This synthesizes and inserts the block "impl" struct, invoke function,
|
||||
|
|
|
@ -980,8 +980,8 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
|
|||
ObjCMethodDecl *OMD = *I;
|
||||
RewriteObjCMethodDecl(OMD, ResultStr);
|
||||
SourceLocation LocStart = OMD->getLocStart();
|
||||
SourceLocation LocEnd = OMD->getBody(*Context)->getLocStart();
|
||||
|
||||
SourceLocation LocEnd = OMD->getCompoundBody(*Context)->getLocStart();
|
||||
|
||||
const char *startBuf = SM->getCharacterData(LocStart);
|
||||
const char *endBuf = SM->getCharacterData(LocEnd);
|
||||
ReplaceText(LocStart, endBuf-startBuf,
|
||||
|
@ -996,7 +996,7 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) {
|
|||
ObjCMethodDecl *OMD = *I;
|
||||
RewriteObjCMethodDecl(OMD, ResultStr);
|
||||
SourceLocation LocStart = OMD->getLocStart();
|
||||
SourceLocation LocEnd = OMD->getBody(*Context)->getLocStart();
|
||||
SourceLocation LocEnd = OMD->getCompoundBody(*Context)->getLocStart();
|
||||
|
||||
const char *startBuf = SM->getCharacterData(LocStart);
|
||||
const char *endBuf = SM->getCharacterData(LocEnd);
|
||||
|
@ -1426,6 +1426,7 @@ Stmt *RewriteObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S,
|
|||
buf += "}\n";
|
||||
|
||||
// Insert all these *after* the statement body.
|
||||
// FIXME: If this should support Obj-C++, support CXXTryStmt
|
||||
if (isa<CompoundStmt>(S->getBody())) {
|
||||
SourceLocation endBodyLoc = OrigEnd.getFileLocWithOffset(1);
|
||||
InsertText(endBodyLoc, buf.c_str(), buf.size());
|
||||
|
@ -4489,7 +4490,8 @@ void RewriteObjC::HandleDeclInMainFile(Decl *D) {
|
|||
// definitions using the same code.
|
||||
RewriteBlocksInFunctionProtoType(FD->getType(), FD);
|
||||
|
||||
if (CompoundStmt *Body = FD->getBody(*Context)) {
|
||||
// FIXME: If this should support Obj-C++, support CXXTryStmt
|
||||
if (CompoundStmt *Body = FD->getCompoundBody(*Context)) {
|
||||
CurFunctionDef = FD;
|
||||
CollectPropertySetters(Body);
|
||||
CurrentBody = Body;
|
||||
|
|
Loading…
Reference in New Issue