diff options
-rw-r--r-- | include/clang/AST/Stmt.h | 40 | ||||
-rw-r--r-- | include/clang/AST/StmtNodes.def | 3 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 2 | ||||
-rw-r--r-- | lib/AST/Stmt.cpp | 14 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 20 | ||||
-rw-r--r-- | lib/AST/StmtSerialization.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 6 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 28 | ||||
-rw-r--r-- | test/SemaCXX/try-catch.cpp | 5 |
10 files changed, 131 insertions, 7 deletions
diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index 6695518587..a8eed16a6b 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -1238,6 +1238,46 @@ public: static CXXCatchStmt* CreateImpl(llvm::Deserializer& D, ASTContext& C); }; +/// CXXTryStmt - A C++ try block, including all handlers. +class CXXTryStmt : public Stmt { + SourceLocation TryLoc; + // First place is the guarded CompoundStatement. Subsequent are the handlers. + // More than three handlers should be rare. + llvm::SmallVector<Stmt*, 4> Stmts; + +public: + CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, + Stmt **handlers, unsigned numHandlers); + + virtual SourceRange getSourceRange() const { + return SourceRange(TryLoc, Stmts.back()->getLocEnd()); + } + + CompoundStmt *getTryBlock() { return llvm::cast<CompoundStmt>(Stmts[0]); } + const CompoundStmt *getTryBlock() const { + return llvm::cast<CompoundStmt>(Stmts[0]); + } + + unsigned getNumHandlers() const { return Stmts.size() - 1; } + CXXCatchStmt *getHandler(unsigned i) { + return llvm::cast<CXXCatchStmt>(Stmts[i + 1]); + } + const CXXCatchStmt *getHandler(unsigned i) const { + return llvm::cast<CXXCatchStmt>(Stmts[i + 1]); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CXXTryStmtClass; + } + static bool classof(const CXXTryStmt *) { return true; } + + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + + virtual void EmitImpl(llvm::Serializer& S) const; + static CXXTryStmt* CreateImpl(llvm::Deserializer& D, ASTContext& C); +}; + } // end namespace clang #endif diff --git a/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index d009957500..27b7848d16 100644 --- a/include/clang/AST/StmtNodes.def +++ b/include/clang/AST/StmtNodes.def @@ -55,8 +55,9 @@ STMT(ObjCForCollectionStmt, Stmt) // C++ statements STMT(CXXCatchStmt, Stmt) +STMT(CXXTryStmt , Stmt) -LAST_STMT(CXXCatchStmt) +LAST_STMT(CXXTryStmt) // Expressions. STMT(Expr , Stmt) diff --git a/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index de1500f388..8f15d2e4d7 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/include/clang/Basic/DiagnosticKinds.def @@ -1319,6 +1319,8 @@ DIAG(err_catch_incomplete, ERROR, "cannot catch%select{| pointer to| reference to}1 incomplete type %0") DIAG(err_qualified_catch_declarator, ERROR, "exception declarator cannot be qualified") +DIAG(err_early_catch_all, ERROR, + "catch-all handler must come last") DIAG(err_invalid_use_of_function_type, ERROR, "a function type is not allowed here") diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 079ed4e0da..586e8f986a 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -350,6 +350,18 @@ QualType CXXCatchStmt::getCaughtType() { } void CXXCatchStmt::Destroy(ASTContext& C) { - ExceptionDecl->Destroy(C); + if (ExceptionDecl) + ExceptionDecl->Destroy(C); Stmt::Destroy(C); } + +// CXXTryStmt +Stmt::child_iterator CXXTryStmt::child_begin() { return &Stmts[0]; } +Stmt::child_iterator CXXTryStmt::child_end() { return &Stmts[0]+Stmts.size(); } + +CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, + Stmt **handlers, unsigned numHandlers) + : Stmt(CXXTryStmtClass), TryLoc(tryLoc) { + Stmts.push_back(tryBlock); + Stmts.insert(Stmts.end(), handlers, handlers + numHandlers); +} diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 61cd89f70f..521478953f 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -52,6 +52,7 @@ namespace { void PrintRawDecl(Decl *D); void PrintRawDeclStmt(DeclStmt *S); void PrintRawIfStmt(IfStmt *If); + void PrintRawCXXCatchStmt(CXXCatchStmt *Catch); void PrintExpr(Expr *E) { if (E) @@ -474,14 +475,29 @@ void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) { OS << "\n"; } -void StmtPrinter::VisitCXXCatchStmt(CXXCatchStmt *Node) { - Indent() << "catch ("; +void StmtPrinter::PrintRawCXXCatchStmt(CXXCatchStmt *Node) { + OS << "catch ("; if (Decl *ExDecl = Node->getExceptionDecl()) PrintRawDecl(ExDecl); else OS << "..."; OS << ") "; PrintRawCompoundStmt(cast<CompoundStmt>(Node->getHandlerBlock())); +} + +void StmtPrinter::VisitCXXCatchStmt(CXXCatchStmt *Node) { + Indent(); + PrintRawCXXCatchStmt(Node); + OS << "\n"; +} + +void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) { + Indent() << "try "; + PrintRawCompoundStmt(Node->getTryBlock()); + for(unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) { + OS << " "; + PrintRawCXXCatchStmt(Node->getHandler(i)); + } OS << "\n"; } diff --git a/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp index 2d6f755719..a6c95b9c04 100644 --- a/lib/AST/StmtSerialization.cpp +++ b/lib/AST/StmtSerialization.cpp @@ -1540,3 +1540,19 @@ CXXCatchStmt::CreateImpl(llvm::Deserializer& D, ASTContext& C) { Stmt *HandlerBlock = D.ReadOwnedPtr<Stmt>(C); return new CXXCatchStmt(CatchLoc, ExDecl, HandlerBlock); } + +void CXXTryStmt::EmitImpl(llvm::Serializer& S) const { + S.Emit(TryLoc); + S.EmitInt(Stmts.size()); + S.BatchEmitOwnedPtrs(Stmts.size(), &Stmts[0]); +} + +CXXTryStmt * +CXXTryStmt::CreateImpl(llvm::Deserializer& D, ASTContext& C) { + SourceLocation TryLoc = SourceLocation::ReadVal(D); + unsigned size = D.ReadInt(); + llvm::SmallVector<Stmt*, 4> Stmts(size); + D.BatchReadOwnedPtrs<Stmt>(size, &Stmts[0], C); + + return new CXXTryStmt(TryLoc, Stmts[0], &Stmts[1], size - 1); +} diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index c179fe8729..48af5af0a3 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -640,9 +640,9 @@ public: virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclTy *ExDecl, StmtArg HandlerBlock); - //virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc, - // StmtArg TryBlock, - // MultiStmtArg Handlers); + virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc, + StmtArg TryBlock, + MultiStmtArg Handlers); //===--------------------------------------------------------------------===// // Expression Parsing Callbacks: SemaExpr.cpp. diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 4ac7ecb8af..8a37bbbe7b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2058,6 +2058,10 @@ Sema::DeclTy *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) Diag(Begin, diag::err_catch_incomplete) << BaseType << Mode; } + // FIXME: Need to test for ability to copy-construct and destroy the + // exception variable. + // FIXME: Need to check for abstract classes. + IdentifierInfo *II = D.getIdentifier(); if (Decl *PrevDecl = LookupDecl(II, Decl::IDNS_Ordinary, S)) { // The scope should be freshly made just for us. There is just no way diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 6a322ee21c..0c441f7523 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -961,3 +961,31 @@ Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclTy *ExDecl, return Owned(new CXXCatchStmt(CatchLoc, static_cast<VarDecl*>(ExDecl), static_cast<Stmt*>(HandlerBlock.release()))); } + +/// ActOnCXXTryBlock - Takes a try compound-statement and a number of +/// handlers and creates a try statement from them. +Action::OwningStmtResult +Sema::ActOnCXXTryBlock(SourceLocation TryLoc, StmtArg TryBlock, + MultiStmtArg RawHandlers) { + unsigned NumHandlers = RawHandlers.size(); + assert(NumHandlers > 0 && + "The parser shouldn't call this if there are no handlers."); + Stmt **Handlers = reinterpret_cast<Stmt**>(RawHandlers.get()); + + for(unsigned i = 0; i < NumHandlers - 1; ++i) { + CXXCatchStmt *Handler = llvm::cast<CXXCatchStmt>(Handlers[i]); + if (!Handler->getExceptionDecl()) + return StmtError(Diag(Handler->getLocStart(), diag::err_early_catch_all)); + } + // FIXME: We should detect handlers for the same type as an earlier one. + // This one is rather easy. + // FIXME: We should detect handlers that cannot catch anything because an + // earlier handler catches a superclass. Need to find a method that is not + // quadratic for this. + // Neither of these are explicitly forbidden, but every compiler detects them + // and warns. + + RawHandlers.release(); + return Owned(new CXXTryStmt(TryLoc, static_cast<Stmt*>(TryBlock.release()), + Handlers, NumHandlers)); +} diff --git a/test/SemaCXX/try-catch.cpp b/test/SemaCXX/try-catch.cpp index 920a1d59c7..97dbaee10d 100644 --- a/test/SemaCXX/try-catch.cpp +++ b/test/SemaCXX/try-catch.cpp @@ -16,4 +16,9 @@ void f() } catch(...) { int j = i; // expected-error {{use of undeclared identifier 'i'}} } + + try { + } catch(...) { // expected-error {{catch-all handler must come last}} + } catch(int) { + } } |