diff options
Diffstat (limited to 'lib/AST/Stmt.cpp')
-rw-r--r-- | lib/AST/Stmt.cpp | 357 |
1 files changed, 261 insertions, 96 deletions
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index a041006c905e..116291bfa1ef 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -76,6 +76,14 @@ const char *Stmt::getStmtClassName() const { return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name; } +// Check that no statement / expression class is polymorphic. LLVM style RTTI +// should be used instead. If absolutely needed an exception can still be added +// here by defining the appropriate macro (but please don't do this). +#define STMT(CLASS, PARENT) \ + static_assert(!std::is_polymorphic<CLASS>::value, \ + #CLASS " should not be polymorphic!"); +#include "clang/AST/StmtNodes.inc" + void Stmt::PrintStats() { // Ensure the table is primed. getStmtInfoTableEntry(Stmt::NullStmtClass); @@ -113,17 +121,23 @@ void Stmt::EnableStatistics() { Stmt *Stmt::IgnoreImplicit() { Stmt *s = this; - if (auto *ewc = dyn_cast<ExprWithCleanups>(s)) - s = ewc->getSubExpr(); + Stmt *lasts = nullptr; - if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s)) - s = mte->GetTemporaryExpr(); + while (s != lasts) { + lasts = s; - if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s)) - s = bte->getSubExpr(); + if (auto *fe = dyn_cast<FullExpr>(s)) + s = fe->getSubExpr(); - while (auto *ice = dyn_cast<ImplicitCastExpr>(s)) - s = ice->getSubExpr(); + if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s)) + s = mte->GetTemporaryExpr(); + + if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s)) + s = bte->getSubExpr(); + + if (auto *ice = dyn_cast<ImplicitCastExpr>(s)) + s = ice->getSubExpr(); + } return s; } @@ -185,30 +199,26 @@ namespace { return bad(); } - typedef SourceLocation getLocStart_t() const; - template <class T> good implements_getLocStart(getLocStart_t T::*) { + typedef SourceLocation getBeginLoc_t() const; + template <class T> good implements_getBeginLoc(getBeginLoc_t T::*) { return good(); } LLVM_ATTRIBUTE_UNUSED - static bad implements_getLocStart(getLocStart_t Stmt::*) { - return bad(); - } + static bad implements_getBeginLoc(getBeginLoc_t Stmt::*) { return bad(); } typedef SourceLocation getLocEnd_t() const; - template <class T> good implements_getLocEnd(getLocEnd_t T::*) { + template <class T> good implements_getEndLoc(getLocEnd_t T::*) { return good(); } LLVM_ATTRIBUTE_UNUSED - static bad implements_getLocEnd(getLocEnd_t Stmt::*) { - return bad(); - } + static bad implements_getEndLoc(getLocEnd_t Stmt::*) { return bad(); } #define ASSERT_IMPLEMENTS_children(type) \ (void) is_good(implements_children(&type::children)) -#define ASSERT_IMPLEMENTS_getLocStart(type) \ - (void) is_good(implements_getLocStart(&type::getLocStart)) -#define ASSERT_IMPLEMENTS_getLocEnd(type) \ - (void) is_good(implements_getLocEnd(&type::getLocEnd)) +#define ASSERT_IMPLEMENTS_getBeginLoc(type) \ + (void)is_good(implements_getBeginLoc(&type::getBeginLoc)) +#define ASSERT_IMPLEMENTS_getEndLoc(type) \ + (void)is_good(implements_getEndLoc(&type::getEndLoc)) } // namespace @@ -217,10 +227,10 @@ namespace { LLVM_ATTRIBUTE_UNUSED static inline void check_implementations() { #define ABSTRACT_STMT(type) -#define STMT(type, base) \ - ASSERT_IMPLEMENTS_children(type); \ - ASSERT_IMPLEMENTS_getLocStart(type); \ - ASSERT_IMPLEMENTS_getLocEnd(type); +#define STMT(type, base) \ + ASSERT_IMPLEMENTS_children(type); \ + ASSERT_IMPLEMENTS_getBeginLoc(type); \ + ASSERT_IMPLEMENTS_getEndLoc(type); #include "clang/AST/StmtNodes.inc" } @@ -257,8 +267,8 @@ namespace { template <class S> SourceRange getSourceRangeImpl(const Stmt *stmt, SourceRange (Stmt::*v)() const) { - return SourceRange(static_cast<const S*>(stmt)->getLocStart(), - static_cast<const S*>(stmt)->getLocEnd()); + return SourceRange(static_cast<const S *>(stmt)->getBeginLoc(), + static_cast<const S *>(stmt)->getEndLoc()); } } // namespace @@ -275,36 +285,41 @@ SourceRange Stmt::getSourceRange() const { llvm_unreachable("unknown statement kind!"); } -SourceLocation Stmt::getLocStart() const { -// llvm::errs() << "getLocStart() for " << getStmtClassName() << "\n"; +SourceLocation Stmt::getBeginLoc() const { + // llvm::errs() << "getBeginLoc() for " << getStmtClassName() << "\n"; switch (getStmtClass()) { case Stmt::NoStmtClass: llvm_unreachable("statement without class"); #define ABSTRACT_STMT(type) -#define STMT(type, base) \ - case Stmt::type##Class: \ - return static_cast<const type*>(this)->getLocStart(); +#define STMT(type, base) \ + case Stmt::type##Class: \ + return static_cast<const type *>(this)->getBeginLoc(); #include "clang/AST/StmtNodes.inc" } llvm_unreachable("unknown statement kind"); } -SourceLocation Stmt::getLocEnd() const { +SourceLocation Stmt::getEndLoc() const { switch (getStmtClass()) { case Stmt::NoStmtClass: llvm_unreachable("statement without class"); #define ABSTRACT_STMT(type) -#define STMT(type, base) \ - case Stmt::type##Class: \ - return static_cast<const type*>(this)->getLocEnd(); +#define STMT(type, base) \ + case Stmt::type##Class: \ + return static_cast<const type *>(this)->getEndLoc(); #include "clang/AST/StmtNodes.inc" } llvm_unreachable("unknown statement kind"); } +int64_t Stmt::getID(const ASTContext &Context) const { + return Context.getAllocator().identifyKnownAlignedObject<Stmt>(this); +} + CompoundStmt::CompoundStmt(ArrayRef<Stmt *> Stmts, SourceLocation LB, SourceLocation RB) - : Stmt(CompoundStmtClass), LBraceLoc(LB), RBraceLoc(RB) { + : Stmt(CompoundStmtClass), RBraceLoc(RB) { CompoundStmtBits.NumStmts = Stmts.size(); setStmts(Stmts); + CompoundStmtBits.LBraceLoc = LB; } void CompoundStmt::setStmts(ArrayRef<Stmt *> Stmts) { @@ -789,51 +804,99 @@ void MSAsmStmt::initialize(const ASTContext &C, StringRef asmstr, }); } -IfStmt::IfStmt(const ASTContext &C, SourceLocation IL, bool IsConstexpr, - Stmt *init, VarDecl *var, Expr *cond, Stmt *then, - SourceLocation EL, Stmt *elsev) - : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) { +IfStmt::IfStmt(const ASTContext &Ctx, SourceLocation IL, bool IsConstexpr, + Stmt *Init, VarDecl *Var, Expr *Cond, Stmt *Then, + SourceLocation EL, Stmt *Else) + : Stmt(IfStmtClass) { + bool HasElse = Else != nullptr; + bool HasVar = Var != nullptr; + bool HasInit = Init != nullptr; + IfStmtBits.HasElse = HasElse; + IfStmtBits.HasVar = HasVar; + IfStmtBits.HasInit = HasInit; + setConstexpr(IsConstexpr); - setConditionVariable(C, var); - SubExprs[INIT] = init; - SubExprs[COND] = cond; - SubExprs[THEN] = then; - SubExprs[ELSE] = elsev; -} -VarDecl *IfStmt::getConditionVariable() const { - if (!SubExprs[VAR]) + setCond(Cond); + setThen(Then); + if (HasElse) + setElse(Else); + if (HasVar) + setConditionVariable(Ctx, Var); + if (HasInit) + setInit(Init); + + setIfLoc(IL); + if (HasElse) + setElseLoc(EL); +} + +IfStmt::IfStmt(EmptyShell Empty, bool HasElse, bool HasVar, bool HasInit) + : Stmt(IfStmtClass, Empty) { + IfStmtBits.HasElse = HasElse; + IfStmtBits.HasVar = HasVar; + IfStmtBits.HasInit = HasInit; +} + +IfStmt *IfStmt::Create(const ASTContext &Ctx, SourceLocation IL, + bool IsConstexpr, Stmt *Init, VarDecl *Var, Expr *Cond, + Stmt *Then, SourceLocation EL, Stmt *Else) { + bool HasElse = Else != nullptr; + bool HasVar = Var != nullptr; + bool HasInit = Init != nullptr; + void *Mem = Ctx.Allocate( + totalSizeToAlloc<Stmt *, SourceLocation>( + NumMandatoryStmtPtr + HasElse + HasVar + HasInit, HasElse), + alignof(IfStmt)); + return new (Mem) + IfStmt(Ctx, IL, IsConstexpr, Init, Var, Cond, Then, EL, Else); +} + +IfStmt *IfStmt::CreateEmpty(const ASTContext &Ctx, bool HasElse, bool HasVar, + bool HasInit) { + void *Mem = Ctx.Allocate( + totalSizeToAlloc<Stmt *, SourceLocation>( + NumMandatoryStmtPtr + HasElse + HasVar + HasInit, HasElse), + alignof(IfStmt)); + return new (Mem) IfStmt(EmptyShell(), HasElse, HasVar, HasInit); +} + +VarDecl *IfStmt::getConditionVariable() { + auto *DS = getConditionVariableDeclStmt(); + if (!DS) return nullptr; - - auto *DS = cast<DeclStmt>(SubExprs[VAR]); return cast<VarDecl>(DS->getSingleDecl()); } -void IfStmt::setConditionVariable(const ASTContext &C, VarDecl *V) { +void IfStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) { + assert(hasVarStorage() && + "This if statement has no storage for a condition variable!"); + if (!V) { - SubExprs[VAR] = nullptr; + getTrailingObjects<Stmt *>()[varOffset()] = nullptr; return; } SourceRange VarRange = V->getSourceRange(); - SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), - VarRange.getEnd()); + getTrailingObjects<Stmt *>()[varOffset()] = new (Ctx) + DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd()); } bool IfStmt::isObjCAvailabilityCheck() const { - return isa<ObjCAvailabilityCheckExpr>(SubExprs[COND]); + return isa<ObjCAvailabilityCheckExpr>(getCond()); } ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP) - : Stmt(ForStmtClass), ForLoc(FL), LParenLoc(LP), RParenLoc(RP) + : Stmt(ForStmtClass), LParenLoc(LP), RParenLoc(RP) { SubExprs[INIT] = Init; setConditionVariable(C, condVar); SubExprs[COND] = Cond; SubExprs[INC] = Inc; SubExprs[BODY] = Body; + ForStmtBits.ForLoc = FL; } VarDecl *ForStmt::getConditionVariable() const { @@ -855,66 +918,125 @@ void ForStmt::setConditionVariable(const ASTContext &C, VarDecl *V) { VarRange.getEnd()); } -SwitchStmt::SwitchStmt(const ASTContext &C, Stmt *init, VarDecl *Var, - Expr *cond) - : Stmt(SwitchStmtClass), FirstCase(nullptr, false) { - setConditionVariable(C, Var); - SubExprs[INIT] = init; - SubExprs[COND] = cond; - SubExprs[BODY] = nullptr; +SwitchStmt::SwitchStmt(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, + Expr *Cond) + : Stmt(SwitchStmtClass), FirstCase(nullptr) { + bool HasInit = Init != nullptr; + bool HasVar = Var != nullptr; + SwitchStmtBits.HasInit = HasInit; + SwitchStmtBits.HasVar = HasVar; + SwitchStmtBits.AllEnumCasesCovered = false; + + setCond(Cond); + setBody(nullptr); + if (HasInit) + setInit(Init); + if (HasVar) + setConditionVariable(Ctx, Var); + + setSwitchLoc(SourceLocation{}); } -VarDecl *SwitchStmt::getConditionVariable() const { - if (!SubExprs[VAR]) - return nullptr; +SwitchStmt::SwitchStmt(EmptyShell Empty, bool HasInit, bool HasVar) + : Stmt(SwitchStmtClass, Empty) { + SwitchStmtBits.HasInit = HasInit; + SwitchStmtBits.HasVar = HasVar; + SwitchStmtBits.AllEnumCasesCovered = false; +} + +SwitchStmt *SwitchStmt::Create(const ASTContext &Ctx, Stmt *Init, VarDecl *Var, + Expr *Cond) { + bool HasInit = Init != nullptr; + bool HasVar = Var != nullptr; + void *Mem = Ctx.Allocate( + totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasInit + HasVar), + alignof(SwitchStmt)); + return new (Mem) SwitchStmt(Ctx, Init, Var, Cond); +} - auto *DS = cast<DeclStmt>(SubExprs[VAR]); +SwitchStmt *SwitchStmt::CreateEmpty(const ASTContext &Ctx, bool HasInit, + bool HasVar) { + void *Mem = Ctx.Allocate( + totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasInit + HasVar), + alignof(SwitchStmt)); + return new (Mem) SwitchStmt(EmptyShell(), HasInit, HasVar); +} + +VarDecl *SwitchStmt::getConditionVariable() { + auto *DS = getConditionVariableDeclStmt(); + if (!DS) + return nullptr; return cast<VarDecl>(DS->getSingleDecl()); } -void SwitchStmt::setConditionVariable(const ASTContext &C, VarDecl *V) { +void SwitchStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) { + assert(hasVarStorage() && + "This switch statement has no storage for a condition variable!"); + if (!V) { - SubExprs[VAR] = nullptr; + getTrailingObjects<Stmt *>()[varOffset()] = nullptr; return; } SourceRange VarRange = V->getSourceRange(); - SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), - VarRange.getEnd()); + getTrailingObjects<Stmt *>()[varOffset()] = new (Ctx) + DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd()); } -Stmt *SwitchCase::getSubStmt() { - if (isa<CaseStmt>(this)) - return cast<CaseStmt>(this)->getSubStmt(); - return cast<DefaultStmt>(this)->getSubStmt(); +WhileStmt::WhileStmt(const ASTContext &Ctx, VarDecl *Var, Expr *Cond, + Stmt *Body, SourceLocation WL) + : Stmt(WhileStmtClass) { + bool HasVar = Var != nullptr; + WhileStmtBits.HasVar = HasVar; + + setCond(Cond); + setBody(Body); + if (HasVar) + setConditionVariable(Ctx, Var); + + setWhileLoc(WL); } -WhileStmt::WhileStmt(const ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, - SourceLocation WL) - : Stmt(WhileStmtClass) { - setConditionVariable(C, Var); - SubExprs[COND] = cond; - SubExprs[BODY] = body; - WhileLoc = WL; +WhileStmt::WhileStmt(EmptyShell Empty, bool HasVar) + : Stmt(WhileStmtClass, Empty) { + WhileStmtBits.HasVar = HasVar; } -VarDecl *WhileStmt::getConditionVariable() const { - if (!SubExprs[VAR]) - return nullptr; +WhileStmt *WhileStmt::Create(const ASTContext &Ctx, VarDecl *Var, Expr *Cond, + Stmt *Body, SourceLocation WL) { + bool HasVar = Var != nullptr; + void *Mem = + Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasVar), + alignof(WhileStmt)); + return new (Mem) WhileStmt(Ctx, Var, Cond, Body, WL); +} + +WhileStmt *WhileStmt::CreateEmpty(const ASTContext &Ctx, bool HasVar) { + void *Mem = + Ctx.Allocate(totalSizeToAlloc<Stmt *>(NumMandatoryStmtPtr + HasVar), + alignof(WhileStmt)); + return new (Mem) WhileStmt(EmptyShell(), HasVar); +} - auto *DS = cast<DeclStmt>(SubExprs[VAR]); +VarDecl *WhileStmt::getConditionVariable() { + auto *DS = getConditionVariableDeclStmt(); + if (!DS) + return nullptr; return cast<VarDecl>(DS->getSingleDecl()); } -void WhileStmt::setConditionVariable(const ASTContext &C, VarDecl *V) { +void WhileStmt::setConditionVariable(const ASTContext &Ctx, VarDecl *V) { + assert(hasVarStorage() && + "This while statement has no storage for a condition variable!"); + if (!V) { - SubExprs[VAR] = nullptr; + getTrailingObjects<Stmt *>()[varOffset()] = nullptr; return; } SourceRange VarRange = V->getSourceRange(); - SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), VarRange.getBegin(), - VarRange.getEnd()); + getTrailingObjects<Stmt *>()[varOffset()] = new (Ctx) + DeclStmt(DeclGroupRef(V), VarRange.getBegin(), VarRange.getEnd()); } // IndirectGotoStmt @@ -925,11 +1047,54 @@ LabelDecl *IndirectGotoStmt::getConstantTarget() { } // ReturnStmt -const Expr* ReturnStmt::getRetValue() const { - return cast_or_null<Expr>(RetExpr); -} -Expr* ReturnStmt::getRetValue() { - return cast_or_null<Expr>(RetExpr); +ReturnStmt::ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate) + : Stmt(ReturnStmtClass), RetExpr(E) { + bool HasNRVOCandidate = NRVOCandidate != nullptr; + ReturnStmtBits.HasNRVOCandidate = HasNRVOCandidate; + if (HasNRVOCandidate) + setNRVOCandidate(NRVOCandidate); + setReturnLoc(RL); +} + +ReturnStmt::ReturnStmt(EmptyShell Empty, bool HasNRVOCandidate) + : Stmt(ReturnStmtClass, Empty) { + ReturnStmtBits.HasNRVOCandidate = HasNRVOCandidate; +} + +ReturnStmt *ReturnStmt::Create(const ASTContext &Ctx, SourceLocation RL, + Expr *E, const VarDecl *NRVOCandidate) { + bool HasNRVOCandidate = NRVOCandidate != nullptr; + void *Mem = Ctx.Allocate(totalSizeToAlloc<const VarDecl *>(HasNRVOCandidate), + alignof(ReturnStmt)); + return new (Mem) ReturnStmt(RL, E, NRVOCandidate); +} + +ReturnStmt *ReturnStmt::CreateEmpty(const ASTContext &Ctx, + bool HasNRVOCandidate) { + void *Mem = Ctx.Allocate(totalSizeToAlloc<const VarDecl *>(HasNRVOCandidate), + alignof(ReturnStmt)); + return new (Mem) ReturnStmt(EmptyShell(), HasNRVOCandidate); +} + +// CaseStmt +CaseStmt *CaseStmt::Create(const ASTContext &Ctx, Expr *lhs, Expr *rhs, + SourceLocation caseLoc, SourceLocation ellipsisLoc, + SourceLocation colonLoc) { + bool CaseStmtIsGNURange = rhs != nullptr; + void *Mem = Ctx.Allocate( + totalSizeToAlloc<Stmt *, SourceLocation>( + NumMandatoryStmtPtr + CaseStmtIsGNURange, CaseStmtIsGNURange), + alignof(CaseStmt)); + return new (Mem) CaseStmt(lhs, rhs, caseLoc, ellipsisLoc, colonLoc); +} + +CaseStmt *CaseStmt::CreateEmpty(const ASTContext &Ctx, + bool CaseStmtIsGNURange) { + void *Mem = Ctx.Allocate( + totalSizeToAlloc<Stmt *, SourceLocation>( + NumMandatoryStmtPtr + CaseStmtIsGNURange, CaseStmtIsGNURange), + alignof(CaseStmt)); + return new (Mem) CaseStmt(EmptyShell(), CaseStmtIsGNURange); } SEHTryStmt::SEHTryStmt(bool IsCXXTry, SourceLocation TryLoc, Stmt *TryBlock, |