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);
|
void ReadInRec(llvm::Deserializer& D, ASTContext& C);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // end namespace clang
|
} // end namespace clang
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace clang {
|
||||||
class Expr;
|
class Expr;
|
||||||
class Decl;
|
class Decl;
|
||||||
class ScopedDecl;
|
class ScopedDecl;
|
||||||
|
class QualType;
|
||||||
class IdentifierInfo;
|
class IdentifierInfo;
|
||||||
class SourceManager;
|
class SourceManager;
|
||||||
class StringLiteral;
|
class StringLiteral;
|
||||||
|
@ -1202,6 +1203,41 @@ public:
|
||||||
static ObjCAtThrowStmt* CreateImpl(llvm::Deserializer& D, ASTContext& C);
|
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
|
} // end namespace clang
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -53,7 +53,10 @@ STMT(ObjCAtSynchronizedStmt , Stmt)
|
||||||
// Obj-C2 statements
|
// Obj-C2 statements
|
||||||
STMT(ObjCForCollectionStmt, Stmt)
|
STMT(ObjCForCollectionStmt, Stmt)
|
||||||
|
|
||||||
LAST_STMT(ObjCForCollectionStmt)
|
// C++ statements
|
||||||
|
STMT(CXXCatchStmt, Stmt)
|
||||||
|
|
||||||
|
LAST_STMT(CXXCatchStmt)
|
||||||
|
|
||||||
// Expressions.
|
// Expressions.
|
||||||
STMT(Expr , Stmt)
|
STMT(Expr , Stmt)
|
||||||
|
|
|
@ -1315,6 +1315,10 @@ DIAG(err_decrement_bool, ERROR,
|
||||||
"cannot decrement expression of type bool")
|
"cannot decrement expression of type bool")
|
||||||
DIAG(warn_increment_bool, WARNING,
|
DIAG(warn_increment_bool, WARNING,
|
||||||
"incrementing expression of type bool is deprecated")
|
"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,
|
DIAG(err_invalid_use_of_function_type, ERROR,
|
||||||
"a function type is not allowed here")
|
"a function type is not allowed here")
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "clang/AST/Stmt.h"
|
#include "clang/AST/Stmt.h"
|
||||||
#include "clang/AST/ExprCXX.h"
|
#include "clang/AST/ExprCXX.h"
|
||||||
#include "clang/AST/ExprObjC.h"
|
#include "clang/AST/ExprObjC.h"
|
||||||
|
#include "clang/AST/Type.h"
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|
||||||
static struct StmtClassNameTable {
|
static struct StmtClassNameTable {
|
||||||
|
@ -333,3 +334,22 @@ Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() {
|
||||||
return &SubStmts[0]+END_EXPR;
|
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";
|
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.
|
// Expr printing methods.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -242,6 +242,9 @@ Stmt* Stmt::Create(Deserializer& D, ASTContext& C) {
|
||||||
|
|
||||||
case CXXDependentNameExprClass:
|
case CXXDependentNameExprClass:
|
||||||
return CXXDependentNameExpr::CreateImpl(D, C);
|
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);
|
SourceLocation L = SourceLocation::ReadVal(D);
|
||||||
return new CXXDependentNameExpr(N, Ty, L);
|
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;
|
DeclTy *ExceptionDecl = 0;
|
||||||
if (Tok.isNot(tok::ellipsis)) {
|
if (Tok.isNot(tok::ellipsis)) {
|
||||||
DeclSpec DS;
|
DeclSpec DS;
|
||||||
ParseDeclarationSpecifiers(DS);
|
if (ParseCXXTypeSpecifierSeq(DS))
|
||||||
|
return StmtError();
|
||||||
Declarator ExDecl(DS, Declarator::CXXCatchContext);
|
Declarator ExDecl(DS, Declarator::CXXCatchContext);
|
||||||
ParseDeclarator(ExDecl);
|
ParseDeclarator(ExDecl);
|
||||||
ExceptionDecl = Actions.ActOnExceptionDeclarator(CurScope, ExDecl);
|
ExceptionDecl = Actions.ActOnExceptionDeclarator(CurScope, ExDecl);
|
||||||
|
|
|
@ -636,10 +636,10 @@ public:
|
||||||
ExprTy *SynchExpr,
|
ExprTy *SynchExpr,
|
||||||
StmtTy *SynchBody);
|
StmtTy *SynchBody);
|
||||||
|
|
||||||
//virtual DeclTy *ActOnExceptionDeclarator(Scope *S, Declarator &D);
|
virtual DeclTy *ActOnExceptionDeclarator(Scope *S, Declarator &D);
|
||||||
//virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
|
virtual OwningStmtResult ActOnCXXCatchBlock(SourceLocation CatchLoc,
|
||||||
// DeclTy *ExceptionDecl,
|
DeclTy *ExDecl,
|
||||||
// StmtArg HandlerBlock);
|
StmtArg HandlerBlock);
|
||||||
//virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc,
|
//virtual OwningStmtResult ActOnCXXTryBlock(SourceLocation TryLoc,
|
||||||
// StmtArg TryBlock,
|
// StmtArg TryBlock,
|
||||||
// MultiStmtArg Handlers);
|
// MultiStmtArg Handlers);
|
||||||
|
|
|
@ -2026,3 +2026,66 @@ Sema::DeclTy *Sema::ActOnLinkageSpec(SourceLocation Loc,
|
||||||
return LinkageSpecDecl::Create(Context, Loc, Language, dcl);
|
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));
|
static_cast<Stmt*>(SynchExpr), static_cast<Stmt*>(SynchBody));
|
||||||
return SS;
|
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