Partial AST and Sema support for C++ try-catch.

llvm-svn: 61337
This commit is contained in:
Sebastian Redl 2008-12-22 19:15:10 +00:00
parent ed4c443193
commit 54c04d4700
12 changed files with 190 additions and 8 deletions

View File

@ -945,8 +945,6 @@ protected:
void ReadInRec(llvm::Deserializer& D, ASTContext& C);
};
} // end namespace clang
#endif

View File

@ -31,6 +31,7 @@ namespace clang {
class Expr;
class Decl;
class ScopedDecl;
class QualType;
class IdentifierInfo;
class SourceManager;
class StringLiteral;
@ -1202,6 +1203,41 @@ public:
static ObjCAtThrowStmt* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};
/// CXXCatchStmt - This represents a C++ catch block.
class CXXCatchStmt : public Stmt {
SourceLocation CatchLoc;
/// The exception-declaration of the type.
Decl *ExceptionDecl;
/// The handler block.
Stmt *HandlerBlock;
public:
CXXCatchStmt(SourceLocation catchLoc, Decl *exDecl, Stmt *handlerBlock)
: Stmt(CXXCatchStmtClass), CatchLoc(catchLoc), ExceptionDecl(exDecl),
HandlerBlock(handlerBlock) {}
virtual void Destroy(ASTContext& Ctx);
virtual SourceRange getSourceRange() const {
return SourceRange(CatchLoc, HandlerBlock->getLocEnd());
}
Decl *getExceptionDecl() { return ExceptionDecl; }
QualType getCaughtType();
Stmt *getHandlerBlock() { return HandlerBlock; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXCatchStmtClass;
}
static bool classof(const CXXCatchStmt *) { return true; }
virtual child_iterator child_begin();
virtual child_iterator child_end();
virtual void EmitImpl(llvm::Serializer& S) const;
static CXXCatchStmt* CreateImpl(llvm::Deserializer& D, ASTContext& C);
};
} // end namespace clang
#endif

View File

@ -53,7 +53,10 @@ STMT(ObjCAtSynchronizedStmt , Stmt)
// Obj-C2 statements
STMT(ObjCForCollectionStmt, Stmt)
LAST_STMT(ObjCForCollectionStmt)
// C++ statements
STMT(CXXCatchStmt, Stmt)
LAST_STMT(CXXCatchStmt)
// Expressions.
STMT(Expr , Stmt)

View File

@ -1315,6 +1315,10 @@ DIAG(err_decrement_bool, ERROR,
"cannot decrement expression of type bool")
DIAG(warn_increment_bool, WARNING,
"incrementing expression of type bool is deprecated")
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_invalid_use_of_function_type, ERROR,
"a function type is not allowed here")

View File

@ -14,6 +14,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Type.h"
using namespace clang;
static struct StmtClassNameTable {
@ -333,3 +334,22 @@ Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() {
return &SubStmts[0]+END_EXPR;
}
// CXXCatchStmt
Stmt::child_iterator CXXCatchStmt::child_begin() {
return &HandlerBlock;
}
Stmt::child_iterator CXXCatchStmt::child_end() {
return &HandlerBlock + 1;
}
QualType CXXCatchStmt::getCaughtType() {
if (ExceptionDecl)
return llvm::cast<VarDecl>(ExceptionDecl)->getType();
return QualType();
}
void CXXCatchStmt::Destroy(ASTContext& C) {
ExceptionDecl->Destroy(C);
Stmt::Destroy(C);
}

View File

@ -474,6 +474,17 @@ void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) {
OS << "\n";
}
void StmtPrinter::VisitCXXCatchStmt(CXXCatchStmt *Node) {
Indent() << "catch (";
if (Decl *ExDecl = Node->getExceptionDecl())
PrintRawDecl(ExDecl);
else
OS << "...";
OS << ") ";
PrintRawCompoundStmt(cast<CompoundStmt>(Node->getHandlerBlock()));
OS << "\n";
}
//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//

View File

@ -242,6 +242,9 @@ Stmt* Stmt::Create(Deserializer& D, ASTContext& C) {
case CXXDependentNameExprClass:
return CXXDependentNameExpr::CreateImpl(D, C);
case CXXCatchStmtClass:
return CXXCatchStmt::CreateImpl(D, C);
}
}
@ -1523,3 +1526,17 @@ CXXDependentNameExpr::CreateImpl(llvm::Deserializer& D, ASTContext& C) {
SourceLocation L = SourceLocation::ReadVal(D);
return new CXXDependentNameExpr(N, Ty, L);
}
void CXXCatchStmt::EmitImpl(llvm::Serializer& S) const {
S.Emit(CatchLoc);
S.EmitOwnedPtr(ExceptionDecl);
S.EmitOwnedPtr(HandlerBlock);
}
CXXCatchStmt *
CXXCatchStmt::CreateImpl(llvm::Deserializer& D, ASTContext& C) {
SourceLocation CatchLoc = SourceLocation::ReadVal(D);
Decl *ExDecl = D.ReadOwnedPtr<Decl>(C);
Stmt *HandlerBlock = D.ReadOwnedPtr<Stmt>(C);
return new CXXCatchStmt(CatchLoc, ExDecl, HandlerBlock);
}

View File

@ -1314,7 +1314,8 @@ Parser::OwningStmtResult Parser::ParseCXXCatchBlock() {
DeclTy *ExceptionDecl = 0;
if (Tok.isNot(tok::ellipsis)) {
DeclSpec DS;
ParseDeclarationSpecifiers(DS);
if (ParseCXXTypeSpecifierSeq(DS))
return StmtError();
Declarator ExDecl(DS, Declarator::CXXCatchContext);
ParseDeclarator(ExDecl);
ExceptionDecl = Actions.ActOnExceptionDeclarator(CurScope, ExDecl);

View File

@ -636,10 +636,10 @@ public:
ExprTy *SynchExpr,
StmtTy *SynchBody);
//virtual DeclTy *ActOnExceptionDeclarator(Scope *S, Declarator &D);
//virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
// DeclTy *ExceptionDecl,
// StmtArg HandlerBlock);
virtual DeclTy *ActOnExceptionDeclarator(Scope *S, Declarator &D);
virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
DeclTy *ExDecl,
StmtArg HandlerBlock);
//virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc,
// StmtArg TryBlock,
// MultiStmtArg Handlers);

View File

@ -2026,3 +2026,66 @@ Sema::DeclTy *Sema::ActOnLinkageSpec(SourceLocation Loc,
return LinkageSpecDecl::Create(Context, Loc, Language, dcl);
}
/// ActOnExceptionDeclarator - Parsed the exception-declarator in a C++ catch
/// handler.
Sema::DeclTy *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D)
{
QualType ExDeclType = GetTypeForDeclarator(D, S);
SourceLocation Begin = D.getDeclSpec().getSourceRange().getBegin();
bool Invalid = false;
// Arrays and functions decay.
if (ExDeclType->isArrayType())
ExDeclType = Context.getArrayDecayedType(ExDeclType);
else if (ExDeclType->isFunctionType())
ExDeclType = Context.getPointerType(ExDeclType);
// C++ 15.3p1: The exception-declaration shall not denote an incomplete type.
// The exception-declaration shall not denote a pointer or reference to an
// incomplete type, other than [cv] void*.
QualType BaseType = ExDeclType;
int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference
if (const PointerType *Ptr = BaseType->getAsPointerType()) {
BaseType = Ptr->getPointeeType();
Mode = 1;
} else if(const ReferenceType *Ref = BaseType->getAsReferenceType()) {
BaseType = Ref->getPointeeType();
Mode = 2;
}
if ((Mode == 0 || !BaseType->isVoidType()) && BaseType->isIncompleteType()) {
Invalid = true;
Diag(Begin, diag::err_catch_incomplete) << BaseType << Mode;
}
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
// it contains any previous declaration.
assert(!S->isDeclScope(PrevDecl));
if (PrevDecl->isTemplateParameter()) {
// Maybe we will complain about the shadowed template parameter.
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), PrevDecl);
}
}
VarDecl *ExDecl = VarDecl::Create(Context, CurContext, D.getIdentifierLoc(),
II, ExDeclType, VarDecl::None, 0, Begin);
if (D.getInvalidType() || Invalid)
ExDecl->setInvalidDecl();
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_catch_declarator)
<< D.getCXXScopeSpec().getRange();
ExDecl->setInvalidDecl();
}
// Add the exception declaration into this scope.
S->AddDecl(ExDecl);
if (II)
IdResolver.AddDecl(ExDecl);
ProcessDeclAttributes(ExDecl, D);
return ExDecl;
}

View File

@ -951,3 +951,13 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprTy *SynchExpr,
static_cast<Stmt*>(SynchExpr), static_cast<Stmt*>(SynchBody));
return SS;
}
/// ActOnCXXCatchBlock - Takes an exception declaration and a handler block
/// and creates a proper catch handler from them.
Action::OwningStmtResult
Sema::ActOnCXXCatchBlock(SourceLocation CatchLoc, DeclTy *ExDecl,
StmtArg HandlerBlock) {
// There's nothing to test that ActOnExceptionDecl didn't already test.
return Owned(new CXXCatchStmt(CatchLoc, static_cast<VarDecl*>(ExDecl),
static_cast<Stmt*>(HandlerBlock.release())));
}

View File

@ -0,0 +1,19 @@
// RUN: clang -fsyntax-only -verify %s
struct A;
void f()
{
try {
} catch(int i) { // expected-note {{previous definition}}
int j = i;
int i; // expected-error {{redefinition of 'i'}}
} catch(float i) {
} catch(void v) { // expected-error {{cannot catch incomplete type 'void'}}
} catch(A a) { // expected-error {{cannot catch incomplete type 'struct A'}}
} catch(A *a) { // expected-error {{cannot catch pointer to incomplete type 'struct A'}}
} catch(A &a) { // expected-error {{cannot catch reference to incomplete type 'struct A'}}
} catch(...) {
int j = i; // expected-error {{use of undeclared identifier 'i'}}
}
}