]> granicus.if.org Git - clang/commitdiff
Implement template instantiation for Objective-C++ @throw statements.
authorDouglas Gregor <dgregor@apple.com>
Thu, 22 Apr 2010 21:44:01 +0000 (21:44 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 22 Apr 2010 21:44:01 +0000 (21:44 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102133 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/Sema.h
lib/Sema/SemaStmt.cpp
lib/Sema/TreeTransform.h
test/SemaObjCXX/instantiate-stmt.mm [new file with mode: 0644]

index 6b8aca9ccd37e0e43180179dcd5719a252b675e1..e3c8597485ea88ee8e33170d4c6ab7e52f698e24 100644 (file)
@@ -1687,6 +1687,8 @@ public:
                                               StmtArg Try,
                                               StmtArg Catch, StmtArg Finally);
 
+  virtual OwningStmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc,
+                                                ExprArg Throw);
   virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
                                                 ExprArg Throw,
                                                 Scope *CurScope);
index cb553932596cbe13d9c2627f0fffd48c864fb9d8..4e460f4bf5698c61f0338cbf1ba29596f8f26a4b 100644 (file)
@@ -1542,10 +1542,28 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc,
                                            Finally.takeAs<Stmt>()));
 }
 
+Sema::OwningStmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc,
+                                                  ExprArg ThrowE) {
+  Expr *Throw = static_cast<Expr *>(ThrowE.get());
+  if (Throw) {
+    QualType ThrowType = Throw->getType();
+    // Make sure the expression type is an ObjC pointer or "void *".
+    if (!ThrowType->isDependentType() &&
+        !ThrowType->isObjCObjectPointerType()) {
+      const PointerType *PT = ThrowType->getAs<PointerType>();
+      if (!PT || !PT->getPointeeType()->isVoidType())
+        return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
+                         << Throw->getType() << Throw->getSourceRange());
+    }
+  }
+  
+  return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowE.takeAs<Expr>()));
+}
+
 Action::OwningStmtResult
-Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) {
-  Expr *ThrowExpr = expr.takeAs<Expr>();
-  if (!ThrowExpr) {
+Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg Throw, 
+                           Scope *CurScope) {
+  if (!Throw.get()) {
     // @throw without an expression designates a rethrow (which much occur
     // in the context of an @catch clause).
     Scope *AtCatchParent = CurScope;
@@ -1553,17 +1571,9 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, ExprArg expr,Scope *CurScope) {
       AtCatchParent = AtCatchParent->getParent();
     if (!AtCatchParent)
       return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch));
-  } else {
-    QualType ThrowType = ThrowExpr->getType();
-    // Make sure the expression type is an ObjC pointer or "void *".
-    if (!ThrowType->isObjCObjectPointerType()) {
-      const PointerType *PT = ThrowType->getAs<PointerType>();
-      if (!PT || !PT->getPointeeType()->isVoidType())
-        return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object)
-                        << ThrowExpr->getType() << ThrowExpr->getSourceRange());
-    }
-  }
-  return Owned(new (Context) ObjCAtThrowStmt(AtLoc, ThrowExpr));
+  } 
+  
+  return BuildObjCAtThrowStmt(AtLoc, move(Throw));
 }
 
 Action::OwningStmtResult
index a86510055fed4b02918da148f99d905c98a3c2da..db44a36ccfd773bbf55d38a5ab7f44af94edd453 100644 (file)
@@ -890,6 +890,15 @@ public:
                                   RParenLoc, MSAsm);
   }
   
+  /// \brief Build a new Objective-C throw statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildObjCAtThrowStmt(SourceLocation AtLoc,
+                                          ExprArg Operand) {
+    return getSema().BuildObjCAtThrowStmt(AtLoc, move(Operand));
+  }
+  
   /// \brief Build a new C++ exception declaration.
   ///
   /// By default, performs semantic analysis to build the new decaration.
@@ -3649,9 +3658,18 @@ TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
 template<typename Derived>
 Sema::OwningStmtResult
 TreeTransform<Derived>::TransformObjCAtThrowStmt(ObjCAtThrowStmt *S) {
-  // FIXME: Implement this
-  assert(false && "Cannot transform an Objective-C @throw statement");
-  return SemaRef.Owned(S->Retain());
+  OwningExprResult Operand(SemaRef);
+  if (S->getThrowExpr()) {
+    Operand = getDerived().TransformExpr(S->getThrowExpr());
+    if (Operand.isInvalid())
+      return getSema().StmtError();
+  }
+  
+  if (!getDerived().AlwaysRebuild() &&
+      Operand.get() == S->getThrowExpr())
+    return getSema().Owned(S->Retain());
+    
+  return getDerived().RebuildObjCAtThrowStmt(S->getThrowLoc(), move(Operand));
 }
 
 template<typename Derived>
diff --git a/test/SemaObjCXX/instantiate-stmt.mm b/test/SemaObjCXX/instantiate-stmt.mm
new file mode 100644 (file)
index 0000000..4c477aa
--- /dev/null
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+@interface NSException
+@end
+
+// @throw
+template<typename T>
+void throw_test(T value) {
+  @throw value; // expected-error{{@throw requires an Objective-C object type ('int' invalid)}}
+}
+
+template void throw_test(NSException *);
+template void throw_test(int); // expected-note{{in instantiation of}}
+
+