]> granicus.if.org Git - clang/commitdiff
Partial AST and Sema support for C++ try-catch.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Mon, 22 Dec 2008 19:15:10 +0000 (19:15 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Mon, 22 Dec 2008 19:15:10 +0000 (19:15 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61337 91177308-0d34-0410-b5e6-96231b3b80d8

12 files changed:
include/clang/AST/DeclCXX.h
include/clang/AST/Stmt.h
include/clang/AST/StmtNodes.def
include/clang/Basic/DiagnosticKinds.def
lib/AST/Stmt.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtSerialization.cpp
lib/Parse/ParseStmt.cpp
lib/Sema/Sema.h
lib/Sema/SemaDeclCXX.cpp
lib/Sema/SemaStmt.cpp
test/SemaCXX/try-catch.cpp [new file with mode: 0644]

index 0e9c5287c4806053f1f5b82b5c85e4189f780d85..f5089785b9df6f9a84b8047ba27d15573f30ca53 100644 (file)
@@ -945,8 +945,6 @@ protected:
   void ReadInRec(llvm::Deserializer& D, ASTContext& C);
 };
 
-  
-
 } // end namespace clang
 
 #endif
index b6e6456ca2be92fe6c9ad9f1251d1e680c1db587..6695518587534664553997608eb84566cc2f194d 100644 (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
index 939325ac1f411424a110e2430b418b4760b0f3eb..d009957500d44b071f92c753f249ad07807cd8bf 100644 (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)
index bad9819ec8e5cc4abfd571dc96ebc990f9f953bb..de1500f38858a5af06234727e4ce40a45a9ada7b 100644 (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")
index 2308159f5d56e17d78a3f40cf40e22aa9ecc7da1..079ed4e0daca4edbbd6d836f0602e5d4e7aefb93 100644 (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);
+}
index 81e158e657e65ab11d00a5efa8d8540c7c5eae9b..61cd89f70fac17c39bcf0d980a1d5f0828c54c6d 100644 (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.
 //===----------------------------------------------------------------------===//
index d12ecd0d93a17a90fa8a7f5e0ec159b1f9091453..2d6f755719570bcf42fe57a2f67be8a6d4733e0c 100644 (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);
+}
index 81a9765555dad3fd4011bcab03cf3b20686e2074..c853ecf8842b0f4aae986169a1737d2c5f1ffd32 100644 (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);
index f8923b4bf82f62c3335a2bafcfeaa808e21c7456..c179fe87296df84355f04a0a0abf3e891e0ba6a2 100644 (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);
index f2f02e21250651b370686514a527e6c955e6e628..4ac7ecb8afe5435fba328cf375bf3dcc44849344 100644 (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;
+}
index 22a9617eb7f5b4565ea9c74fae9d6db5b25cfef0..6a322ee21cb82924283ac537a741ae8bbc968456 100644 (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())));
+}
diff --git a/test/SemaCXX/try-catch.cpp b/test/SemaCXX/try-catch.cpp
new file mode 100644 (file)
index 0000000..920a1d5
--- /dev/null
@@ -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'}}
+  }
+}