diff options
Diffstat (limited to 'lib/Sema/SemaTemplateInstantiateStmt.cpp')
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateStmt.cpp | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/lib/Sema/SemaTemplateInstantiateStmt.cpp b/lib/Sema/SemaTemplateInstantiateStmt.cpp new file mode 100644 index 0000000..1f69479 --- /dev/null +++ b/lib/Sema/SemaTemplateInstantiateStmt.cpp @@ -0,0 +1,443 @@ +//===--- SemaTemplateInstantiateStmt.cpp - C++ Template Stmt Instantiation ===/ +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +//===----------------------------------------------------------------------===/ +// +// This file implements C++ template instantiation for statements. +// +//===----------------------------------------------------------------------===/ +#include "Sema.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Parse/DeclSpec.h" +#include "llvm/Support/Compiler.h" +using namespace clang; + +namespace { + class VISIBILITY_HIDDEN TemplateStmtInstantiator + : public StmtVisitor<TemplateStmtInstantiator, Sema::OwningStmtResult> { + Sema &SemaRef; + const TemplateArgumentList &TemplateArgs; + + template<typename T> + Sema::FullExprArg FullExpr(T &expr) { + return SemaRef.FullExpr(expr); + } + + public: + typedef Sema::OwningExprResult OwningExprResult; + typedef Sema::OwningStmtResult OwningStmtResult; + + TemplateStmtInstantiator(Sema &SemaRef, + const TemplateArgumentList &TemplateArgs) + : SemaRef(SemaRef), TemplateArgs(TemplateArgs) { } + + // Declare VisitXXXStmt nodes for all of the statement kinds. +#define STMT(Type, Base) OwningStmtResult Visit##Type(Type *S); +#define EXPR(Type, Base) +#include "clang/AST/StmtNodes.def" + + // Visit an expression (which will use the expression + // instantiator). + OwningStmtResult VisitExpr(Expr *E); + + // Base case. I'm supposed to ignore this. + OwningStmtResult VisitStmt(Stmt *S) { + S->dump(); + assert(false && "Cannot instantiate this kind of statement"); + return SemaRef.StmtError(); + } + }; +} + +//===----------------------------------------------------------------------===/ +// Common/C statements +//===----------------------------------------------------------------------===/ +Sema::OwningStmtResult TemplateStmtInstantiator::VisitDeclStmt(DeclStmt *S) { + llvm::SmallVector<Decl *, 4> Decls; + for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) { + Decl *Instantiated = SemaRef.InstantiateDecl(*D, SemaRef.CurContext, + TemplateArgs); + if (!Instantiated) + return SemaRef.StmtError(); + + Decls.push_back(Instantiated); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(*D, Instantiated); + } + + return SemaRef.Owned(new (SemaRef.Context) DeclStmt( + DeclGroupRef::Create(SemaRef.Context, + &Decls[0], + Decls.size()), + S->getStartLoc(), + S->getEndLoc())); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitNullStmt(NullStmt *S) { + return SemaRef.Owned(S->Clone(SemaRef.Context)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitLabelStmt(LabelStmt *S) { + OwningStmtResult SubStmt = Visit(S->getSubStmt()); + + if (SubStmt.isInvalid()) + return SemaRef.StmtError(); + + // FIXME: Pass the real colon loc in. + return SemaRef.ActOnLabelStmt(S->getIdentLoc(), S->getID(), SourceLocation(), + move(SubStmt)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitGotoStmt(GotoStmt *S) { + return SemaRef.ActOnGotoStmt(S->getGotoLoc(), S->getLabelLoc(), + S->getLabel()->getID()); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + OwningExprResult Target = SemaRef.InstantiateExpr(S->getTarget(), + TemplateArgs); + if (Target.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnIndirectGotoStmt(S->getGotoLoc(), S->getStarLoc(), + move(Target)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitBreakStmt(BreakStmt *S) { + return SemaRef.Owned(S->Clone(SemaRef.Context)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitContinueStmt(ContinueStmt *S) { + return SemaRef.Owned(S->Clone(SemaRef.Context)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitReturnStmt(ReturnStmt *S) { + Sema::OwningExprResult Result = SemaRef.ExprEmpty(); + if (Expr *E = S->getRetValue()) { + Result = SemaRef.InstantiateExpr(E, TemplateArgs); + + if (Result.isInvalid()) + return SemaRef.StmtError(); + } + + return SemaRef.ActOnReturnStmt(S->getReturnLoc(), FullExpr(Result)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitCompoundStmt(CompoundStmt *S) { + return SemaRef.InstantiateCompoundStmt(S, TemplateArgs, false); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitSwitchCase(SwitchCase *S) { + assert(false && "SwitchCase statements are never directly instantiated"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitCaseStmt(CaseStmt *S) { + // Instantiate left-hand case value. + OwningExprResult LHS = SemaRef.InstantiateExpr(S->getLHS(), TemplateArgs); + if (LHS.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate right-hand case value (for the GNU case-range extension). + OwningExprResult RHS = SemaRef.InstantiateExpr(S->getRHS(), TemplateArgs); + if (RHS.isInvalid()) + return SemaRef.StmtError(); + + // Build the case statement. + OwningStmtResult Case = SemaRef.ActOnCaseStmt(S->getCaseLoc(), + move(LHS), + S->getEllipsisLoc(), + move(RHS), + S->getColonLoc()); + if (Case.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the statement following the case + OwningStmtResult SubStmt = SemaRef.InstantiateStmt(S->getSubStmt(), + TemplateArgs); + if (SubStmt.isInvalid()) + return SemaRef.StmtError(); + + SemaRef.ActOnCaseStmtBody(Case.get(), move(SubStmt)); + return move(Case); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitDefaultStmt(DefaultStmt *S) { + // Instantiate the statement following the default case + OwningStmtResult SubStmt = SemaRef.InstantiateStmt(S->getSubStmt(), + TemplateArgs); + if (SubStmt.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnDefaultStmt(S->getDefaultLoc(), + S->getColonLoc(), + move(SubStmt), + /*CurScope=*/0); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitIfStmt(IfStmt *S) { + // Instantiate the condition + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the "then" branch. + OwningStmtResult Then = SemaRef.InstantiateStmt(S->getThen(), TemplateArgs); + if (Then.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the "else" branch. + OwningStmtResult Else = SemaRef.InstantiateStmt(S->getElse(), TemplateArgs); + if (Else.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnIfStmt(S->getIfLoc(), FullExpr(Cond), move(Then), + S->getElseLoc(), move(Else)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitSwitchStmt(SwitchStmt *S) { + // Instantiate the condition. + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Start the switch statement itself. + OwningStmtResult Switch = SemaRef.ActOnStartOfSwitchStmt(move(Cond)); + if (Switch.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the body of the switch statement. + OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + // Complete the switch statement. + return SemaRef.ActOnFinishSwitchStmt(S->getSwitchLoc(), move(Switch), + move(Body)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitWhileStmt(WhileStmt *S) { + // Instantiate the condition + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the body + OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnWhileStmt(S->getWhileLoc(), FullExpr(Cond), move(Body)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitDoStmt(DoStmt *S) { + // Instantiate the condition + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the body + OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnDoStmt(S->getDoLoc(), move(Body), S->getWhileLoc(), + move(Cond)); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitForStmt(ForStmt *S) { + // Instantiate the initialization statement + OwningStmtResult Init = SemaRef.InstantiateStmt(S->getInit(), TemplateArgs); + if (Init.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the condition + OwningExprResult Cond = SemaRef.InstantiateExpr(S->getCond(), TemplateArgs); + if (Cond.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the increment + OwningExprResult Inc = SemaRef.InstantiateExpr(S->getInc(), TemplateArgs); + if (Inc.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the body + OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs); + if (Body.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.ActOnForStmt(S->getForLoc(), S->getLParenLoc(), + move(Init), move(Cond), move(Inc), + S->getRParenLoc(), move(Body)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitAsmStmt(AsmStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an 'asm' statement"); + return SemaRef.StmtError(); +} + +//===----------------------------------------------------------------------===/ +// C++ statements +//===----------------------------------------------------------------------===/ +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitCXXTryStmt(CXXTryStmt *S) { + // Instantiate the try block itself. + OwningStmtResult TryBlock = VisitCompoundStmt(S->getTryBlock()); + if (TryBlock.isInvalid()) + return SemaRef.StmtError(); + + // Instantiate the handlers. + ASTOwningVector<&ActionBase::DeleteStmt> Handlers(SemaRef); + for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) { + OwningStmtResult Handler = VisitCXXCatchStmt(S->getHandler(I)); + if (Handler.isInvalid()) + return SemaRef.StmtError(); + + Handlers.push_back(Handler.takeAs<Stmt>()); + } + + return SemaRef.ActOnCXXTryBlock(S->getTryLoc(), move(TryBlock), + move_arg(Handlers)); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitCXXCatchStmt(CXXCatchStmt *S) { + // Instantiate the exception declaration, if any. + VarDecl *Var = 0; + if (S->getExceptionDecl()) { + VarDecl *ExceptionDecl = S->getExceptionDecl(); + QualType T = SemaRef.InstantiateType(ExceptionDecl->getType(), + TemplateArgs, + ExceptionDecl->getLocation(), + ExceptionDecl->getDeclName()); + if (T.isNull()) + return SemaRef.StmtError(); + + Var = SemaRef.BuildExceptionDeclaration(0, T, + ExceptionDecl->getIdentifier(), + ExceptionDecl->getLocation(), + /*FIXME: Inaccurate*/ + SourceRange(ExceptionDecl->getLocation())); + if (Var->isInvalidDecl()) { + Var->Destroy(SemaRef.Context); + return SemaRef.StmtError(); + } + + // Introduce the exception declaration into scope. + SemaRef.CurrentInstantiationScope->InstantiatedLocal(ExceptionDecl, Var); + } + + // Instantiate the actual exception handler. + OwningStmtResult Handler = Visit(S->getHandlerBlock()); + if (Handler.isInvalid()) { + if (Var) + Var->Destroy(SemaRef.Context); + return SemaRef.StmtError(); + } + + return SemaRef.Owned(new (SemaRef.Context) CXXCatchStmt(S->getCatchLoc(), + Var, + Handler.takeAs<Stmt>())); +} + +//===----------------------------------------------------------------------===/ +// Objective-C statements +//===----------------------------------------------------------------------===/ +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C @finally statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCAtSynchronizedStmt( + ObjCAtSynchronizedStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C @synchronized statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C @try statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCForCollectionStmt( + ObjCForCollectionStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C \"for\" statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C @throw statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult +TemplateStmtInstantiator::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { + // FIXME: Implement this + assert(false && "Cannot instantiate an Objective-C @catch statement"); + return SemaRef.StmtError(); +} + +Sema::OwningStmtResult TemplateStmtInstantiator::VisitExpr(Expr *E) { + Sema::OwningExprResult Result = SemaRef.InstantiateExpr(E, TemplateArgs); + if (Result.isInvalid()) + return SemaRef.StmtError(); + + return SemaRef.Owned(Result.takeAs<Stmt>()); +} + +Sema::OwningStmtResult +Sema::InstantiateStmt(Stmt *S, const TemplateArgumentList &TemplateArgs) { + if (!S) + return Owned((Stmt *)0); + + TemplateStmtInstantiator Instantiator(*this, TemplateArgs); + return Instantiator.Visit(S); +} + +Sema::OwningStmtResult +Sema::InstantiateCompoundStmt(CompoundStmt *S, + const TemplateArgumentList &TemplateArgs, + bool isStmtExpr) { + if (!S) + return Owned((Stmt *)0); + + TemplateStmtInstantiator Instantiator(*this, TemplateArgs); + ASTOwningVector<&ActionBase::DeleteStmt> Statements(*this); + for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end(); + B != BEnd; ++B) { + OwningStmtResult Result = Instantiator.Visit(*B); + if (Result.isInvalid()) + return StmtError(); + + Statements.push_back(Result.takeAs<Stmt>()); + } + + return ActOnCompoundStmt(S->getLBracLoc(), S->getRBracLoc(), + move_arg(Statements), isStmtExpr); +} |