Full AST support and better Sema support for C++ try-catch.

llvm-svn: 61346
This commit is contained in:
Sebastian Redl 2008-12-22 21:35:02 +00:00
parent 014caa431c
commit 9b244a8797
10 changed files with 131 additions and 7 deletions

View File

@ -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

View File

@ -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)

View File

@ -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")

View File

@ -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);
}

View File

@ -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";
}

View File

@ -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);
}

View File

@ -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.

View File

@ -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

View File

@ -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));
}

View File

@ -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) {
}
}