Partial AST and Sema support for C++ try-catch.
llvm-svn: 61337
This commit is contained in:
parent
ed4c443193
commit
54c04d4700
|
@ -945,8 +945,6 @@ protected:
|
|||
void ReadInRec(llvm::Deserializer& D, ASTContext& C);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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())));
|
||||
}
|
||||
|
|
|
@ -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'}}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue