Refactor the instantiation of statements into a generic tree
transformation.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79519 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index e734d07..ae359bb 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -18,6 +18,9 @@
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
 #include "clang/AST/ExprObjC.h"
+#include "clang/AST/Stmt.h"
+#include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
 #include "clang/Parse/Ownership.h"
 #include "clang/Parse/Designator.h"
 #include "clang/Lex/Preprocessor.h"
@@ -61,7 +64,7 @@
 ///
 /// For more fine-grained transformations, subclasses can replace any of the
 /// \c TransformXXX functions (where XXX is the name of an AST node, e.g.,
-/// PointerType) to alter the transformation. As mentioned previously,
+/// PointerType, StmtExpr) to alter the transformation. As mentioned previously,
 /// replacing TransformTemplateTypeParmType() allows template instantiation
 /// to substitute template arguments for their corresponding template 
 /// parameters. Additionally, subclasses can override the \c RebuildXXX
@@ -76,9 +79,6 @@
 /// operands have not changed (\c AlwaysRebuild()), and customize the
 /// default locations and entity names used for type-checking
 /// (\c getBaseLocation(), \c getBaseEntity()).
-///
-/// FIXME: In the future, TreeTransform will support transformation of
-/// statements and expressions as well as types.
 template<typename Derived>
 class TreeTransform {
 protected:
@@ -90,6 +90,7 @@
   typedef Sema::StmtArg StmtArg;
   typedef Sema::ExprArg ExprArg;
   typedef Sema::MultiExprArg MultiExprArg;
+  typedef Sema::MultiStmtArg MultiStmtArg;
   
   /// \brief Initializes a new tree transformer.
   TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { }
@@ -191,7 +192,13 @@
        
   /// \brief Transform the given statement.
   ///
-  /// FIXME: At the moment, subclasses must override this.
+  /// By default, this routine transforms a statement by delegating to the 
+  /// appropriate TransformXXXStmt function to transform a specific kind of
+  /// statement or the TransformExpr() function to transform an expression.
+  /// Subclasses may override this function to transform statements using some
+  /// other mechanism.
+  ///
+  /// \returns the transformed statement.
   OwningStmtResult TransformStmt(Stmt *S);
   
   /// \brief Transform the given expression.
@@ -222,6 +229,12 @@
   /// By default, acts as the identity function on declarations. Subclasses
   /// may override this function to provide alternate behavior.
   Decl *TransformDecl(Decl *D) { return D; }
+
+  /// \brief Transform the definition of the given declaration.
+  ///
+  /// By default, invokes TransformDecl() to transform the declaration. 
+  /// Subclasses may override this function to provide alternate behavior.
+  Decl *TransformDefinition(Decl *D) { return getDerived().TransformDecl(D); }
   
   /// \brief Transform the given nested-name-specifier.
   ///
@@ -251,12 +264,10 @@
   QualType Transform##CLASS##Type(const CLASS##Type *T);
 #include "clang/AST/TypeNodes.def"      
 
-  OwningStmtResult TransformCompoundStmt(Stmt *S, bool IsStmtExpr) {
-    // FIXME: Actually handle this transformation properly.
-    return getDerived().TransformStmt(S);
-  }
+  OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
                                          
-#define STMT(Node, Parent)
+#define STMT(Node, Parent)                        \
+  OwningStmtResult Transform##Node(Node *S);
 #define EXPR(Node, Parent)                        \
   OwningExprResult Transform##Node(Node *E);
 #define ABSTRACT_EXPR(Node, Parent)
@@ -540,6 +551,204 @@
                                    const IdentifierInfo &II);
   
   
+  /// \brief Build a new compound statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildCompoundStmt(SourceLocation LBraceLoc,
+                                       MultiStmtArg Statements,
+                                       SourceLocation RBraceLoc,
+                                       bool IsStmtExpr) {
+    return getSema().ActOnCompoundStmt(LBraceLoc, RBraceLoc, move(Statements),
+                                       IsStmtExpr);
+  }
+
+  /// \brief Build a new case statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildCaseStmt(SourceLocation CaseLoc,
+                                   ExprArg LHS,
+                                   SourceLocation EllipsisLoc,
+                                   ExprArg RHS,
+                                   SourceLocation ColonLoc) {
+    return getSema().ActOnCaseStmt(CaseLoc, move(LHS), EllipsisLoc, move(RHS), 
+                                   ColonLoc);
+  }
+  
+  /// \brief Attach the body to a new case statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildCaseStmtBody(StmtArg S, StmtArg Body) {
+    getSema().ActOnCaseStmtBody(S.get(), move(Body));
+    return move(S);
+  }
+  
+  /// \brief Build a new default statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildDefaultStmt(SourceLocation DefaultLoc, 
+                                      SourceLocation ColonLoc,
+                                      StmtArg SubStmt) {
+    return getSema().ActOnDefaultStmt(DefaultLoc, ColonLoc, move(SubStmt), 
+                                      /*CurScope=*/0);
+  }
+  
+  /// \brief Build a new label statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildLabelStmt(SourceLocation IdentLoc, 
+                                    IdentifierInfo *Id,
+                                    SourceLocation ColonLoc,
+                                    StmtArg SubStmt) {
+    return SemaRef.ActOnLabelStmt(IdentLoc, Id, ColonLoc, move(SubStmt));
+  }
+  
+  /// \brief Build a new "if" statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond, 
+                                 StmtArg Then, SourceLocation ElseLoc, 
+                                 StmtArg Else) {
+    return getSema().ActOnIfStmt(IfLoc, Cond, move(Then), ElseLoc, move(Else));
+  }
+  
+  /// \brief Start building a new switch statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildSwitchStmtStart(ExprArg Cond) {
+    return getSema().ActOnStartOfSwitchStmt(move(Cond));
+  }
+  
+  /// \brief Attach the body to the switch statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildSwitchStmtBody(SourceLocation SwitchLoc, 
+                                         StmtArg Switch, StmtArg Body) {
+    return getSema().ActOnFinishSwitchStmt(SwitchLoc, move(Switch),
+                                         move(Body));
+  }
+
+  /// \brief Build a new while statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildWhileStmt(SourceLocation WhileLoc,
+                                    Sema::FullExprArg Cond,
+                                    StmtArg Body) {
+    return getSema().ActOnWhileStmt(WhileLoc, Cond, move(Body));
+  }
+  
+  /// \brief Build a new do-while statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildDoStmt(SourceLocation DoLoc, StmtArg Body,
+                                 SourceLocation WhileLoc,
+                                 SourceLocation LParenLoc,
+                                 ExprArg Cond,
+                                 SourceLocation RParenLoc) {
+    return getSema().ActOnDoStmt(DoLoc, move(Body), WhileLoc, LParenLoc, 
+                                 move(Cond), RParenLoc);
+  }
+
+  /// \brief Build a new for statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildForStmt(SourceLocation ForLoc, 
+                                  SourceLocation LParenLoc,
+                                  StmtArg Init, ExprArg Cond, ExprArg Inc,
+                                  SourceLocation RParenLoc, StmtArg Body) {
+    return getSema().ActOnForStmt(ForLoc, LParenLoc, move(Init), move(Cond), 
+                                  move(Inc), RParenLoc, move(Body));
+  }
+  
+  /// \brief Build a new goto statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildGotoStmt(SourceLocation GotoLoc,
+                                   SourceLocation LabelLoc,
+                                   LabelStmt *Label) {
+    return getSema().ActOnGotoStmt(GotoLoc, LabelLoc, Label->getID());
+  }
+
+  /// \brief Build a new indirect goto statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildIndirectGotoStmt(SourceLocation GotoLoc,
+                                           SourceLocation StarLoc,
+                                           ExprArg Target) {
+    return getSema().ActOnIndirectGotoStmt(GotoLoc, StarLoc, move(Target));
+  }
+  
+  /// \brief Build a new return statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildReturnStmt(SourceLocation ReturnLoc,
+                                     ExprArg Result) {
+    
+    return getSema().ActOnReturnStmt(ReturnLoc, move(Result));
+  }
+  
+  /// \brief Build a new declaration statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildDeclStmt(Decl **Decls, unsigned NumDecls,
+                                   SourceLocation StartLoc, 
+                                   SourceLocation EndLoc) {
+    return getSema().Owned(
+             new (getSema().Context) DeclStmt(
+                                        DeclGroupRef::Create(getSema().Context,
+                                                             Decls, NumDecls),
+                                              StartLoc, EndLoc));
+  }
+  
+  /// \brief Build a new C++ exception declaration.
+  ///
+  /// By default, performs semantic analysis to build the new decaration.
+  /// Subclasses may override this routine to provide different behavior.
+  VarDecl *RebuildExceptionDecl(VarDecl *ExceptionDecl, QualType T, 
+                                DeclaratorInfo *Declarator,
+                                IdentifierInfo *Name,
+                                SourceLocation Loc,
+                                SourceRange TypeRange) {
+    return getSema().BuildExceptionDeclaration(0, T, Declarator, Name, Loc, 
+                                               TypeRange);
+  }
+
+  /// \brief Build a new C++ catch statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildCXXCatchStmt(SourceLocation CatchLoc,
+                                       VarDecl *ExceptionDecl,
+                                       StmtArg Handler) {
+    return getSema().Owned(
+             new (getSema().Context) CXXCatchStmt(CatchLoc, ExceptionDecl, 
+                                                  Handler.takeAs<Stmt>()));
+  }
+  
+  /// \brief Build a new C++ try statement.
+  ///
+  /// By default, performs semantic analysis to build the new statement.
+  /// Subclasses may override this routine to provide different behavior.
+  OwningStmtResult RebuildCXXTryStmt(SourceLocation TryLoc,
+                                     StmtArg TryBlock,
+                                     MultiStmtArg Handlers) {
+    return getSema().ActOnCXXTryBlock(TryLoc, move(TryBlock), move(Handlers));
+  }
+  
   /// \brief Build a new expression that references a declaration.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -1311,6 +1520,36 @@
   }
 };
 
+template<typename Derived>
+Sema::OwningStmtResult TreeTransform<Derived>::TransformStmt(Stmt *S) {
+  if (!S)
+    return SemaRef.Owned(S);
+  
+  switch (S->getStmtClass()) {
+  case Stmt::NoStmtClass: break;
+      
+  // Transform individual statement nodes
+#define STMT(Node, Parent)                                              \
+  case Stmt::Node##Class: return getDerived().Transform##Node(cast<Node>(S));
+#define EXPR(Node, Parent)
+#include "clang/AST/StmtNodes.def"
+      
+  // Transform expressions by calling TransformExpr.
+#define STMT(Node, Parent)
+#define EXPR(Node, Parent) case Stmt::Node##Class:
+#include "clang/AST/StmtNodes.def"
+    {
+      Sema::OwningExprResult E = getDerived().TransformExpr(cast<Expr>(S));
+      if (E.isInvalid())
+        return getSema().StmtError();
+      
+      return getSema().Owned(E.takeAs<Stmt>());
+    }
+  }  
+  
+  return SemaRef.Owned(S->Retain());
+}
+  
   
 template<typename Derived>
 Sema::OwningExprResult TreeTransform<Derived>::TransformExpr(Expr *E,
@@ -1333,7 +1572,7 @@
 NestedNameSpecifier *
 TreeTransform<Derived>::TransformNestedNameSpecifier(NestedNameSpecifier *NNS,
                                                      SourceRange Range) {
-  // Instantiate the prefix of this nested name specifier.
+  // Transform the prefix of this nested name specifier.
   NestedNameSpecifier *Prefix = NNS->getPrefix();
   if (Prefix) {
     Prefix = getDerived().TransformNestedNameSpecifier(Prefix, Range);
@@ -2075,6 +2314,458 @@
 }
 
 //===----------------------------------------------------------------------===//
+// Statement transformation
+//===----------------------------------------------------------------------===//
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformNullStmt(NullStmt *S) { 
+  return SemaRef.Owned(S->Retain()); 
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S) {
+  return getDerived().TransformCompoundStmt(S, false);
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S, 
+                                              bool IsStmtExpr) {
+  bool SubStmtChanged = false;
+  ASTOwningVector<&ActionBase::DeleteStmt> Statements(getSema());
+  for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end();
+       B != BEnd; ++B) {
+    OwningStmtResult Result = getDerived().TransformStmt(*B);
+    if (Result.isInvalid())
+      return getSema().StmtError();
+    
+    SubStmtChanged = SubStmtChanged || Result.get() != *B;
+    Statements.push_back(Result.takeAs<Stmt>());
+  }
+  
+  if (!getDerived().AlwaysRebuild() &&
+      !SubStmtChanged)
+    return SemaRef.Owned(S->Retain()); 
+
+  return getDerived().RebuildCompoundStmt(S->getLBracLoc(),
+                                          move_arg(Statements),
+                                          S->getRBracLoc(),
+                                          IsStmtExpr);
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCaseStmt(CaseStmt *S) { 
+  // The case value expressions are not potentially evaluated.
+  EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
+  
+  // Transform the left-hand case value.
+  OwningExprResult LHS = getDerived().TransformExpr(S->getLHS());
+  if (LHS.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Transform the right-hand case value (for the GNU case-range extension).
+  OwningExprResult RHS = getDerived().TransformExpr(S->getRHS());
+  if (RHS.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Build the case statement.
+  // Case statements are always rebuilt so that they will attached to their
+  // transformed switch statement.
+  OwningStmtResult Case = getDerived().RebuildCaseStmt(S->getCaseLoc(),
+                                                       move(LHS),
+                                                       S->getEllipsisLoc(),
+                                                       move(RHS),
+                                                       S->getColonLoc());
+  if (Case.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Transform the statement following the case
+  OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+  if (SubStmt.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Attach the body to the case statement
+  return getDerived().RebuildCaseStmtBody(move(Case), move(SubStmt));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformDefaultStmt(DefaultStmt *S) { 
+  // Transform the statement following the default case
+  OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+  if (SubStmt.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Default statements are always rebuilt
+  return getDerived().RebuildDefaultStmt(S->getDefaultLoc(), S->getColonLoc(),
+                                         move(SubStmt));
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformLabelStmt(LabelStmt *S) { 
+  OwningStmtResult SubStmt = getDerived().TransformStmt(S->getSubStmt());
+  if (SubStmt.isInvalid())
+    return SemaRef.StmtError();
+  
+  // FIXME: Pass the real colon location in.
+  SourceLocation ColonLoc = SemaRef.PP.getLocForEndOfToken(S->getIdentLoc());
+  return getDerived().RebuildLabelStmt(S->getIdentLoc(), S->getID(), ColonLoc,
+                                       move(SubStmt));
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult 
+TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { 
+  // Transform the condition
+  OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+  if (Cond.isInvalid())
+    return SemaRef.StmtError();
+  
+  Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
+  
+  // Transform the "then" branch.
+  OwningStmtResult Then = getDerived().TransformStmt(S->getThen());
+  if (Then.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Transform the "else" branch.
+  OwningStmtResult Else = getDerived().TransformStmt(S->getElse());
+  if (Else.isInvalid())
+    return SemaRef.StmtError();
+  
+  if (!getDerived().AlwaysRebuild() &&
+      FullCond->get() == S->getCond() &&
+      Then.get() == S->getThen() &&
+      Else.get() == S->getElse())
+    return SemaRef.Owned(S->Retain()); 
+  
+  return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, move(Then),
+                                    S->getElseLoc(), move(Else));  
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) { 
+  // Transform the condition.
+  OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+  if (Cond.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Rebuild the switch statement.
+  OwningStmtResult Switch = getDerived().RebuildSwitchStmtStart(move(Cond));
+  if (Switch.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Transform the body of the switch statement.
+  OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+  if (Body.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Complete the switch statement.
+  return getDerived().RebuildSwitchStmtBody(S->getSwitchLoc(), move(Switch),
+                                            move(Body));
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { 
+  // Transform the condition
+  OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+  if (Cond.isInvalid())
+    return SemaRef.StmtError();
+  
+  Sema::FullExprArg FullCond(getSema().FullExpr(Cond));
+  
+  // Transform the body
+  OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+  if (Body.isInvalid())
+    return SemaRef.StmtError();
+  
+  if (!getDerived().AlwaysRebuild() &&
+      FullCond->get() == S->getCond() &&
+      Body.get() == S->getBody())
+    return SemaRef.Owned(S->Retain()); 
+  
+  return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, move(Body));
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformDoStmt(DoStmt *S) {
+  // Transform the condition
+  OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+  if (Cond.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Transform the body
+  OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+  if (Body.isInvalid())
+    return SemaRef.StmtError();
+  
+  if (!getDerived().AlwaysRebuild() &&
+      Cond.get() == S->getCond() &&
+      Body.get() == S->getBody())
+    return SemaRef.Owned(S->Retain()); 
+  
+  return getDerived().RebuildDoStmt(S->getDoLoc(), move(Body), S->getWhileLoc(),
+                                    /*FIXME:*/S->getWhileLoc(), move(Cond),
+                                    S->getRParenLoc());
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformForStmt(ForStmt *S) { 
+  // Transform the initialization statement
+  OwningStmtResult Init = getDerived().TransformStmt(S->getInit());
+  if (Init.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Transform the condition
+  OwningExprResult Cond = getDerived().TransformExpr(S->getCond());
+  if (Cond.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Transform the increment
+  OwningExprResult Inc = getDerived().TransformExpr(S->getInc());
+  if (Inc.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Transform the body
+  OwningStmtResult Body = getDerived().TransformStmt(S->getBody());
+  if (Body.isInvalid())
+    return SemaRef.StmtError();
+  
+  if (!getDerived().AlwaysRebuild() &&
+      Init.get() == S->getInit() &&
+      Cond.get() == S->getCond() &&
+      Inc.get() == S->getInc() &&
+      Body.get() == S->getBody())
+    return SemaRef.Owned(S->Retain()); 
+  
+  return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(),
+                                     move(Init), move(Cond), move(Inc),
+                                     S->getRParenLoc(), move(Body));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult 
+TreeTransform<Derived>::TransformGotoStmt(GotoStmt *S) { 
+  // Goto statements must always be rebuilt, to resolve the label.
+  return getDerived().RebuildGotoStmt(S->getGotoLoc(), S->getLabelLoc(), 
+                                      S->getLabel());
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformIndirectGotoStmt(IndirectGotoStmt *S) { 
+  OwningExprResult Target = getDerived().TransformExpr(S->getTarget());
+  if (Target.isInvalid())
+    return SemaRef.StmtError();
+  
+  if (!getDerived().AlwaysRebuild() &&
+      Target.get() == S->getTarget())
+    return SemaRef.Owned(S->Retain()); 
+
+  return getDerived().RebuildIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(),
+                                              move(Target));
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformContinueStmt(ContinueStmt *S) { 
+  return SemaRef.Owned(S->Retain()); 
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformBreakStmt(BreakStmt *S) { 
+  return SemaRef.Owned(S->Retain()); 
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformReturnStmt(ReturnStmt *S) { 
+  Sema::OwningExprResult Result = getDerived().TransformExpr(S->getRetValue());
+  if (Result.isInvalid())
+    return SemaRef.StmtError();
+
+  // FIXME: We always rebuild the return statement because there is no way 
+  // to tell whether the return type of the function has changed.
+  return getDerived().RebuildReturnStmt(S->getReturnLoc(), move(Result));
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) { 
+  bool DeclChanged = false;
+  llvm::SmallVector<Decl *, 4> Decls;
+  for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end();
+       D != DEnd; ++D) {
+    Decl *Transformed = getDerived().TransformDefinition(*D);
+    if (!Transformed)
+      return SemaRef.StmtError();
+        
+    if (Transformed != *D)
+      DeclChanged = true;
+    
+    Decls.push_back(Transformed);
+  }
+  
+  if (!getDerived().AlwaysRebuild() && !DeclChanged)
+    return SemaRef.Owned(S->Retain()); 
+  
+  return getDerived().RebuildDeclStmt(Decls.data(), Decls.size(), 
+                                      S->getStartLoc(), S->getEndLoc());
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformSwitchCase(SwitchCase *S) { 
+  assert(false && "SwitchCase is abstract and cannot be transformed");
+  return SemaRef.Owned(S->Retain()); 
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) {
+  // FIXME: Implement!
+  assert(false && "Inline assembly cannot be transformed");
+  return SemaRef.Owned(S->Retain()); 
+}
+
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { 
+  // FIXME: Implement this
+  assert(false && "Cannot transform an Objective-C @try statement");
+  return SemaRef.Owned(S->Retain()); 
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtCatchStmt(ObjCAtCatchStmt *S) { 
+  // FIXME: Implement this
+  assert(false && "Cannot transform an Objective-C @catch statement");
+  return SemaRef.Owned(S->Retain());
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { 
+  // FIXME: Implement this
+  assert(false && "Cannot transform an Objective-C @finally statement");
+  return SemaRef.Owned(S->Retain()); 
+}
+  
+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()); 
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCAtSynchronizedStmt(
+                                                  ObjCAtSynchronizedStmt *S) { 
+  // FIXME: Implement this
+  assert(false && "Cannot transform an Objective-C @synchronized statement");
+  return SemaRef.Owned(S->Retain()); 
+}
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformObjCForCollectionStmt(
+                                                  ObjCForCollectionStmt *S) { 
+  // FIXME: Implement this
+  assert(false && "Cannot transform an Objective-C for-each statement");
+  return SemaRef.Owned(S->Retain()); 
+}
+
+
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCXXCatchStmt(CXXCatchStmt *S) {
+  // Transform the exception declaration, if any.
+  VarDecl *Var = 0;
+  if (S->getExceptionDecl()) {
+    VarDecl *ExceptionDecl = S->getExceptionDecl();
+    TemporaryBase Rebase(*this, ExceptionDecl->getLocation(),
+                         ExceptionDecl->getDeclName());
+
+    QualType T = getDerived().TransformType(ExceptionDecl->getType());
+    if (T.isNull())
+      return SemaRef.StmtError();
+    
+    Var = getDerived().RebuildExceptionDecl(ExceptionDecl,
+                                            T,
+                                            ExceptionDecl->getDeclaratorInfo(),
+                                            ExceptionDecl->getIdentifier(),
+                                            ExceptionDecl->getLocation(),
+                                            /*FIXME: Inaccurate*/
+                                    SourceRange(ExceptionDecl->getLocation()));
+    if (!Var || Var->isInvalidDecl()) {
+      if (Var)
+        Var->Destroy(SemaRef.Context);
+      return SemaRef.StmtError();
+    }
+  }
+  
+  // Transform the actual exception handler.
+  OwningStmtResult Handler = getDerived().TransformStmt(S->getHandlerBlock());
+  if (Handler.isInvalid()) {
+    if (Var)
+      Var->Destroy(SemaRef.Context);
+    return SemaRef.StmtError();
+  }
+  
+  if (!getDerived().AlwaysRebuild() &&
+      !Var &&
+      Handler.get() == S->getHandlerBlock())
+    return SemaRef.Owned(S->Retain()); 
+
+  return getDerived().RebuildCXXCatchStmt(S->getCatchLoc(),
+                                          Var,
+                                          move(Handler));
+}
+  
+template<typename Derived>
+Sema::OwningStmtResult
+TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) {
+  // Transform the try block itself.
+  OwningStmtResult TryBlock 
+    = getDerived().TransformCompoundStmt(S->getTryBlock());
+  if (TryBlock.isInvalid())
+    return SemaRef.StmtError();
+  
+  // Transform the handlers.
+  bool HandlerChanged = false;
+  ASTOwningVector<&ActionBase::DeleteStmt> Handlers(SemaRef);
+  for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) {
+    OwningStmtResult Handler 
+      = getDerived().TransformCXXCatchStmt(S->getHandler(I));
+    if (Handler.isInvalid())
+      return SemaRef.StmtError();
+    
+    HandlerChanged = HandlerChanged || Handler.get() != S->getHandler(I);
+    Handlers.push_back(Handler.takeAs<Stmt>());
+  }
+  
+  if (!getDerived().AlwaysRebuild() &&
+      TryBlock.get() == S->getTryBlock() &&
+      !HandlerChanged)
+    return SemaRef.Owned(S->Retain()); 
+
+  return getDerived().RebuildCXXTryStmt(S->getTryLoc(), move(TryBlock),
+                                        move_arg(Handlers));  
+}
+  
+//===----------------------------------------------------------------------===//
 // Expression transformation
 //===----------------------------------------------------------------------===//
 template<typename Derived> 
@@ -2478,12 +3169,12 @@
 TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { 
   Designation Desig;
   
-  // Instantiate the initializer value
+  // transform the initializer value
   OwningExprResult Init = getDerived().TransformExpr(E->getInit());
   if (Init.isInvalid())
     return SemaRef.ExprError();
   
-  // Instantiate the designators.
+  // transform the designators.
   ASTOwningVector<&ActionBase::DeleteExpr, 4> ArrayExprs(SemaRef);
   bool ExprChanged = false;
   for (DesignatedInitExpr::designators_iterator D = E->designators_begin(),
@@ -2943,7 +3634,7 @@
 Sema::OwningExprResult
 TreeTransform<Derived>::TransformCXXConditionDeclExpr(CXXConditionDeclExpr *E) {
   VarDecl *Var 
-    = cast_or_null<VarDecl>(getDerived().TransformDecl(E->getVarDecl()));
+    = cast_or_null<VarDecl>(getDerived().TransformDefinition(E->getVarDecl()));
   if (!Var)
     return SemaRef.ExprError();
   
@@ -2982,7 +3673,7 @@
     PlacementArgs.push_back(Arg.take());
   }
   
-  // Instantiate the constructor arguments (if any).
+  // transform the constructor arguments (if any).
   ASTOwningVector<&ActionBase::DeleteExpr> ConstructorArgs(SemaRef);
   for (unsigned I = 0, N = E->getNumConstructorArgs(); I != N; ++I) {
     OwningExprResult Arg = getDerived().TransformExpr(E->getConstructorArg(I));