diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 0e9c5287c480..f5089785b9df 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -945,8 +945,6 @@ protected: void ReadInRec(llvm::Deserializer& D, ASTContext& C); }; - - } // end namespace clang #endif diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index b6e6456ca2be..669551858753 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -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 diff --git a/clang/include/clang/AST/StmtNodes.def b/clang/include/clang/AST/StmtNodes.def index 939325ac1f41..d009957500d4 100644 --- a/clang/include/clang/AST/StmtNodes.def +++ b/clang/include/clang/AST/StmtNodes.def @@ -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) diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index bad9819ec8e5..de1500f38858 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -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") diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 2308159f5d56..079ed4e0daca 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -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(ExceptionDecl)->getType(); + return QualType(); +} + +void CXXCatchStmt::Destroy(ASTContext& C) { + ExceptionDecl->Destroy(C); + Stmt::Destroy(C); +} diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 81e158e657e6..61cd89f70fac 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -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(Node->getHandlerBlock())); + OS << "\n"; +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/StmtSerialization.cpp b/clang/lib/AST/StmtSerialization.cpp index d12ecd0d93a1..2d6f75571957 100644 --- a/clang/lib/AST/StmtSerialization.cpp +++ b/clang/lib/AST/StmtSerialization.cpp @@ -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(C); + Stmt *HandlerBlock = D.ReadOwnedPtr(C); + return new CXXCatchStmt(CatchLoc, ExDecl, HandlerBlock); +} diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 81a9765555da..c853ecf8842b 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -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); diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index f8923b4bf82f..c179fe87296d 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index f2f02e212506..4ac7ecb8afe5 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -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; +} diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 22a9617eb7f5..6a322ee21cb8 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -951,3 +951,13 @@ Sema::ActOnObjCAtSynchronizedStmt(SourceLocation AtLoc, ExprTy *SynchExpr, static_cast(SynchExpr), static_cast(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(ExDecl), + static_cast(HandlerBlock.release()))); +} diff --git a/clang/test/SemaCXX/try-catch.cpp b/clang/test/SemaCXX/try-catch.cpp new file mode 100644 index 000000000000..920a1d59c747 --- /dev/null +++ b/clang/test/SemaCXX/try-catch.cpp @@ -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'}} + } +}