aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/Stmt.h40
-rw-r--r--include/clang/AST/StmtNodes.def3
-rw-r--r--include/clang/Basic/DiagnosticKinds.def2
-rw-r--r--lib/AST/Stmt.cpp14
-rw-r--r--lib/AST/StmtPrinter.cpp20
-rw-r--r--lib/AST/StmtSerialization.cpp16
-rw-r--r--lib/Sema/Sema.h6
-rw-r--r--lib/Sema/SemaDeclCXX.cpp4
-rw-r--r--lib/Sema/SemaStmt.cpp28
-rw-r--r--test/SemaCXX/try-catch.cpp5
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) {
+ }
}