Implement template instantiation for Objective-C++ @throw statements.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@102133 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 6b8aca9..e3c8597 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1687,6 +1687,8 @@
                                               StmtArg Try,
                                               StmtArg Catch, StmtArg Finally);
 
+  virtual OwningStmtResult BuildObjCAtThrowStmt(SourceLocation AtLoc,
+                                                ExprArg Throw);
   virtual OwningStmtResult ActOnObjCAtThrowStmt(SourceLocation AtLoc,
                                                 ExprArg Throw,
                                                 Scope *CurScope);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index cb55393..4e460f4 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1542,10 +1542,28 @@
                                            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 @@
       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
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index a865100..db44a36 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -890,6 +890,15 @@
                                   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 @@
 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
index 0000000..4c477aa
--- /dev/null
+++ b/test/SemaObjCXX/instantiate-stmt.mm
@@ -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}}
+
+