forked from OSchip/llvm-project
448 lines
16 KiB
C++
448 lines
16 KiB
C++
//===--- 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();
|
|
|
|
Sema::FullExprArg FullCond(FullExpr(Cond));
|
|
|
|
// 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(), FullCond, 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();
|
|
|
|
Sema::FullExprArg FullCond(FullExpr(Cond));
|
|
|
|
// Instantiate the body
|
|
OwningStmtResult Body = SemaRef.InstantiateStmt(S->getBody(), TemplateArgs);
|
|
if (Body.isInvalid())
|
|
return SemaRef.StmtError();
|
|
|
|
return SemaRef.ActOnWhileStmt(S->getWhileLoc(), FullCond, 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(),
|
|
SourceLocation(), move(Cond), S->getRParenLoc());
|
|
}
|
|
|
|
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);
|
|
}
|