diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 0e396c27b239..da3459a0166e 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -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. diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index f9bb7a445061..7d88cf228fc8 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -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); diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 989fdab597fd..e8c554b67bcd 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -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; } diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index e5d7a1d1bdd5..9481ce531710 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -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">; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index dcf4c5affb4b..fdb2327d4b35 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -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); diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 1dd782936f2b..aa0fc702a4e2 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -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(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(FD->Body.get(0)); + return FD->Body.get(0); } } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index a20786035a29..707383af3a8f 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -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 @@ -341,6 +343,21 @@ DeclContext *Decl::castToDeclContext(const Decl *D) { } } +CompoundStmt* Decl::getCompoundBody(ASTContext &Context) const { + return dyn_cast_or_null(getBody(Context)); +} + +SourceLocation Decl::getBodyRBrace(ASTContext &Context) const { + Stmt *Body = getBody(Context); + if (!Body) + return SourceLocation(); + if (CompoundStmt *CS = dyn_cast(Body)) + return CS->getRBracLoc(); + assert(isa(Body) && + "Body can only be CompoundStmt or CXXTryStmt"); + return cast(Body)->getSourceRange().getEnd(); +} + #ifndef NDEBUG void Decl::CheckAccessDeclContext() const { assert((Access != AS_none || isa(this) || diff --git a/clang/lib/Analysis/BugReporter.cpp b/clang/lib/Analysis/BugReporter.cpp index 348ab3d09a7d..397d28b6e2e0 100644 --- a/clang/lib/Analysis/BugReporter.cpp +++ b/clang/lib/Analysis/BugReporter.cpp @@ -189,7 +189,7 @@ PathDiagnosticBuilder::ExecutionContinues(const ExplodedNode* 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())); diff --git a/clang/lib/Analysis/CFRefCount.cpp b/clang/lib/Analysis/CFRefCount.cpp index bb957b89f558..c2369abb2cf6 100644 --- a/clang/lib/Analysis/CFRefCount.cpp +++ b/clang/lib/Analysis/CFRefCount.cpp @@ -3047,11 +3047,11 @@ CFRefLeakReport::getEndPath(BugReporter& br, const ExplodedNode* 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; diff --git a/clang/lib/Analysis/PathDiagnostic.cpp b/clang/lib/Analysis/PathDiagnostic.cpp index 946548e02cc2..1a4af471f5c9 100644 --- a/clang/lib/Analysis/PathDiagnostic.cpp +++ b/clang/lib/Analysis/PathDiagnostic.cpp @@ -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 @@ -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(Body)) + return CS->getSourceRange(); + else + return cast(Body)->getSourceRange(); + } } else { SourceLocation L = D->getLocation(); diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index df49c70ec64a..de89f0d961ae 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -129,7 +129,7 @@ void CodeGenFunction::GenerateObjCMethod(const ObjCMethodDecl *OMD) { DebugInfo = CGM.getDebugInfo(); StartObjCMethod(OMD, OMD->getClassInterface()); EmitStmt(OMD->getBody(getContext())); - FinishFunction(cast(OMD->getBody(getContext()))->getRBracLoc()); + FinishFunction(OMD->getBodyRBrace(getContext())); } // FIXME: I wasn't sure about the synthesis approach. If we end up diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index c05ead5233b5..c74f8344cc8a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -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()); diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index 45eaa746817d..a2f93b46cabd 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -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 '{'?? diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index d4310e0cbf48..c6a373dc5c4d 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -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; } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index fa712e0a9eb3..ce8872873601 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1289,7 +1289,7 @@ bool Parser::ParseAsmOperandsOpt(llvm::SmallVectorImpl &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()); diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index a245ac2156b1..94036dbd86e6 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -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); } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 658e84b067b5..1ea3a9ec3c7c 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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(); - CompoundStmt *Body =cast(static_cast(BodyArg.release())); + Stmt *Body = BodyArg.takeAs(); if (FunctionDecl *FD = dyn_cast_or_null(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 Elements(Body->body_begin(), Body->body_end()); + + CompoundStmt *Compound = isa(Body) ? + cast(Body)->getTryBlock() : + cast(Body); + std::vector 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(); diff --git a/clang/test/Parser/cxx-try.cpp b/clang/test/Parser/cxx-try.cpp index 76b85e840659..8deed35559ce 100644 --- a/clang/test/Parser/cxx-try.cpp +++ b/clang/test/Parser/cxx-try.cpp @@ -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(...) {} diff --git a/clang/tools/clang-cc/RewriteBlocks.cpp b/clang/tools/clang-cc/RewriteBlocks.cpp index a9324e666698..f9ed0ecc095f 100644 --- a/clang/tools/clang-cc/RewriteBlocks.cpp +++ b/clang/tools/clang-cc/RewriteBlocks.cpp @@ -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(RewriteFunctionBody(Body))); // This synthesizes and inserts the block "impl" struct, invoke function, diff --git a/clang/tools/clang-cc/RewriteObjC.cpp b/clang/tools/clang-cc/RewriteObjC.cpp index 5b8fd5268cd4..95b50b832e4b 100644 --- a/clang/tools/clang-cc/RewriteObjC.cpp +++ b/clang/tools/clang-cc/RewriteObjC.cpp @@ -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(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;