diff options
Diffstat (limited to 'contrib/llvm/tools/clang/include/clang/AST/Stmt.h')
-rw-r--r-- | contrib/llvm/tools/clang/include/clang/AST/Stmt.h | 1381 |
1 files changed, 1381 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/include/clang/AST/Stmt.h b/contrib/llvm/tools/clang/include/clang/AST/Stmt.h new file mode 100644 index 0000000..9deae15 --- /dev/null +++ b/contrib/llvm/tools/clang/include/clang/AST/Stmt.h @@ -0,0 +1,1381 @@ +//===--- Stmt.h - Classes for representing statements -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the Stmt interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_STMT_H +#define LLVM_CLANG_AST_STMT_H + +#include "llvm/Support/Casting.h" +#include "llvm/Support/raw_ostream.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/StmtIterator.h" +#include "clang/AST/DeclGroup.h" +#include "clang/AST/FullExpr.h" +#include "llvm/ADT/SmallVector.h" +#include "clang/AST/ASTContext.h" +#include <string> +using llvm::dyn_cast_or_null; + +namespace llvm { + class FoldingSetNodeID; +} + +namespace clang { + class ASTContext; + class Expr; + class Decl; + class ParmVarDecl; + class QualType; + class IdentifierInfo; + class SourceManager; + class StringLiteral; + class SwitchStmt; + + //===----------------------------------------------------------------------===// + // ExprIterator - Iterators for iterating over Stmt* arrays that contain + // only Expr*. This is needed because AST nodes use Stmt* arrays to store + // references to children (to be compatible with StmtIterator). + //===----------------------------------------------------------------------===// + + class Stmt; + class Expr; + + class ExprIterator { + Stmt** I; + public: + ExprIterator(Stmt** i) : I(i) {} + ExprIterator() : I(0) {} + ExprIterator& operator++() { ++I; return *this; } + ExprIterator operator-(size_t i) { return I-i; } + ExprIterator operator+(size_t i) { return I+i; } + Expr* operator[](size_t idx); + // FIXME: Verify that this will correctly return a signed distance. + signed operator-(const ExprIterator& R) const { return I - R.I; } + Expr* operator*() const; + Expr* operator->() const; + bool operator==(const ExprIterator& R) const { return I == R.I; } + bool operator!=(const ExprIterator& R) const { return I != R.I; } + bool operator>(const ExprIterator& R) const { return I > R.I; } + bool operator>=(const ExprIterator& R) const { return I >= R.I; } + }; + + class ConstExprIterator { + const Stmt * const *I; + public: + ConstExprIterator(const Stmt * const *i) : I(i) {} + ConstExprIterator() : I(0) {} + ConstExprIterator& operator++() { ++I; return *this; } + ConstExprIterator operator+(size_t i) const { return I+i; } + ConstExprIterator operator-(size_t i) const { return I-i; } + const Expr * operator[](size_t idx) const; + signed operator-(const ConstExprIterator& R) const { return I - R.I; } + const Expr * operator*() const; + const Expr * operator->() const; + bool operator==(const ConstExprIterator& R) const { return I == R.I; } + bool operator!=(const ConstExprIterator& R) const { return I != R.I; } + bool operator>(const ConstExprIterator& R) const { return I > R.I; } + bool operator>=(const ConstExprIterator& R) const { return I >= R.I; } + }; + +//===----------------------------------------------------------------------===// +// AST classes for statements. +//===----------------------------------------------------------------------===// + +/// Stmt - This represents one statement. +/// +class Stmt { +public: + enum StmtClass { + NoStmtClass = 0, +#define STMT(CLASS, PARENT) CLASS##Class, +#define STMT_RANGE(BASE, FIRST, LAST) \ + first##BASE##Constant = FIRST##Class, \ + last##BASE##Constant = LAST##Class, +#define LAST_STMT_RANGE(BASE, FIRST, LAST) \ + first##BASE##Constant = FIRST##Class, \ + last##BASE##Constant = LAST##Class +#define ABSTRACT_STMT(STMT) +#include "clang/AST/StmtNodes.inc" +}; +private: + /// \brief The statement class. + const unsigned sClass : 8; + + /// \brief The reference count for this statement. + unsigned RefCount : 24; + + // Make vanilla 'new' and 'delete' illegal for Stmts. +protected: + void* operator new(size_t bytes) throw() { + assert(0 && "Stmts cannot be allocated with regular 'new'."); + return 0; + } + void operator delete(void* data) throw() { + assert(0 && "Stmts cannot be released with regular 'delete'."); + } + +public: + // Only allow allocation of Stmts using the allocator in ASTContext + // or by doing a placement new. + void* operator new(size_t bytes, ASTContext& C, + unsigned alignment = 8) throw() { + return ::operator new(bytes, C, alignment); + } + + void* operator new(size_t bytes, ASTContext* C, + unsigned alignment = 8) throw() { + return ::operator new(bytes, *C, alignment); + } + + void* operator new(size_t bytes, void* mem) throw() { + return mem; + } + + void operator delete(void*, ASTContext&, unsigned) throw() { } + void operator delete(void*, ASTContext*, unsigned) throw() { } + void operator delete(void*, std::size_t) throw() { } + void operator delete(void*, void*) throw() { } + +public: + /// \brief A placeholder type used to construct an empty shell of a + /// type, that will be filled in later (e.g., by some + /// de-serialization). + struct EmptyShell { }; + +protected: + /// DestroyChildren - Invoked by destructors of subclasses of Stmt to + /// recursively release child AST nodes. + void DestroyChildren(ASTContext& Ctx); + + /// \brief Construct an empty statement. + explicit Stmt(StmtClass SC, EmptyShell) : sClass(SC), RefCount(1) { + if (Stmt::CollectingStats()) Stmt::addStmtClass(SC); + } + + /// \brief Virtual method that performs the actual destruction of + /// this statement. + /// + /// Subclasses should override this method (not Destroy()) to + /// provide class-specific destruction. + virtual void DoDestroy(ASTContext &Ctx); + +public: + Stmt(StmtClass SC) : sClass(SC), RefCount(1) { + if (Stmt::CollectingStats()) Stmt::addStmtClass(SC); + } + virtual ~Stmt() {} + +#ifndef NDEBUG + /// \brief True if this statement's refcount is in a valid state. + /// Should be used only in assertions. + bool isRetained() const { + return (RefCount >= 1); + } +#endif + + /// \brief Destroy the current statement and its children. + void Destroy(ASTContext &Ctx) { + assert(RefCount >= 1); + if (--RefCount == 0) + DoDestroy(Ctx); + } + + /// \brief Increases the reference count for this statement. + /// + /// Invoke the Retain() operation when this statement or expression + /// is being shared by another owner. + Stmt *Retain() { + assert(RefCount >= 1); + ++RefCount; + return this; + } + + StmtClass getStmtClass() const { + assert(RefCount >= 1 && "Referencing already-destroyed statement!"); + return (StmtClass)sClass; + } + const char *getStmtClassName() const; + + /// SourceLocation tokens are not useful in isolation - they are low level + /// value objects created/interpreted by SourceManager. We assume AST + /// clients will have a pointer to the respective SourceManager. + virtual SourceRange getSourceRange() const = 0; + SourceLocation getLocStart() const { return getSourceRange().getBegin(); } + SourceLocation getLocEnd() const { return getSourceRange().getEnd(); } + + // global temp stats (until we have a per-module visitor) + static void addStmtClass(const StmtClass s); + static bool CollectingStats(bool Enable = false); + static void PrintStats(); + + /// dump - This does a local dump of the specified AST fragment. It dumps the + /// specified node and a few nodes underneath it, but not the whole subtree. + /// This is useful in a debugger. + void dump() const; + void dump(SourceManager &SM) const; + + /// dumpAll - This does a dump of the specified AST fragment and all subtrees. + void dumpAll() const; + void dumpAll(SourceManager &SM) const; + + /// dumpPretty/printPretty - These two methods do a "pretty print" of the AST + /// back to its original source language syntax. + void dumpPretty(ASTContext& Context) const; + void printPretty(llvm::raw_ostream &OS, PrinterHelper *Helper, + const PrintingPolicy &Policy, + unsigned Indentation = 0) const { + printPretty(OS, *(ASTContext*)0, Helper, Policy, Indentation); + } + void printPretty(llvm::raw_ostream &OS, ASTContext &Context, + PrinterHelper *Helper, + const PrintingPolicy &Policy, + unsigned Indentation = 0) const; + + /// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only + /// works on systems with GraphViz (Mac OS X) or dot+gv installed. + void viewAST() const; + + // Implement isa<T> support. + static bool classof(const Stmt *) { return true; } + + /// hasImplicitControlFlow - Some statements (e.g. short circuited operations) + /// contain implicit control-flow in the order their subexpressions + /// are evaluated. This predicate returns true if this statement has + /// such implicit control-flow. Such statements are also specially handled + /// within CFGs. + bool hasImplicitControlFlow() const; + + /// Child Iterators: All subclasses must implement child_begin and child_end + /// to permit easy iteration over the substatements/subexpessions of an + /// AST node. This permits easy iteration over all nodes in the AST. + typedef StmtIterator child_iterator; + typedef ConstStmtIterator const_child_iterator; + + virtual child_iterator child_begin() = 0; + virtual child_iterator child_end() = 0; + + const_child_iterator child_begin() const { + return const_child_iterator(const_cast<Stmt*>(this)->child_begin()); + } + + const_child_iterator child_end() const { + return const_child_iterator(const_cast<Stmt*>(this)->child_end()); + } + + /// \brief Produce a unique representation of the given statement. + /// + /// \brief ID once the profiling operation is complete, will contain + /// the unique representation of the given statement. + /// + /// \brief Context the AST context in which the statement resides + /// + /// \brief Canonical whether the profile should be based on the canonical + /// representation of this statement (e.g., where non-type template + /// parameters are identified by index/level rather than their + /// declaration pointers) or the exact representation of the statement as + /// written in the source. + void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context, + bool Canonical); +}; + +/// DeclStmt - Adaptor class for mixing declarations with statements and +/// expressions. For example, CompoundStmt mixes statements, expressions +/// and declarations (variables, types). Another example is ForStmt, where +/// the first statement can be an expression or a declaration. +/// +class DeclStmt : public Stmt { + DeclGroupRef DG; + SourceLocation StartLoc, EndLoc; + +protected: + virtual void DoDestroy(ASTContext &Ctx); + +public: + DeclStmt(DeclGroupRef dg, SourceLocation startLoc, + SourceLocation endLoc) : Stmt(DeclStmtClass), DG(dg), + StartLoc(startLoc), EndLoc(endLoc) {} + + /// \brief Build an empty declaration statement. + explicit DeclStmt(EmptyShell Empty) : Stmt(DeclStmtClass, Empty) { } + + /// isSingleDecl - This method returns true if this DeclStmt refers + /// to a single Decl. + bool isSingleDecl() const { + return DG.isSingleDecl(); + } + + const Decl *getSingleDecl() const { return DG.getSingleDecl(); } + Decl *getSingleDecl() { return DG.getSingleDecl(); } + + const DeclGroupRef getDeclGroup() const { return DG; } + DeclGroupRef getDeclGroup() { return DG; } + void setDeclGroup(DeclGroupRef DGR) { DG = DGR; } + + SourceLocation getStartLoc() const { return StartLoc; } + void setStartLoc(SourceLocation L) { StartLoc = L; } + SourceLocation getEndLoc() const { return EndLoc; } + void setEndLoc(SourceLocation L) { EndLoc = L; } + + SourceRange getSourceRange() const { + return SourceRange(StartLoc, EndLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == DeclStmtClass; + } + static bool classof(const DeclStmt *) { return true; } + + // Iterators over subexpressions. + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + + typedef DeclGroupRef::iterator decl_iterator; + typedef DeclGroupRef::const_iterator const_decl_iterator; + + decl_iterator decl_begin() { return DG.begin(); } + decl_iterator decl_end() { return DG.end(); } + const_decl_iterator decl_begin() const { return DG.begin(); } + const_decl_iterator decl_end() const { return DG.end(); } +}; + +/// NullStmt - This is the null statement ";": C99 6.8.3p3. +/// +class NullStmt : public Stmt { + SourceLocation SemiLoc; +public: + NullStmt(SourceLocation L) : Stmt(NullStmtClass), SemiLoc(L) {} + + /// \brief Build an empty null statement. + explicit NullStmt(EmptyShell Empty) : Stmt(NullStmtClass, Empty) { } + + SourceLocation getSemiLoc() const { return SemiLoc; } + void setSemiLoc(SourceLocation L) { SemiLoc = L; } + + virtual SourceRange getSourceRange() const { return SourceRange(SemiLoc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == NullStmtClass; + } + static bool classof(const NullStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// CompoundStmt - This represents a group of statements like { stmt stmt }. +/// +class CompoundStmt : public Stmt { + Stmt** Body; + unsigned NumStmts; + SourceLocation LBracLoc, RBracLoc; +public: + CompoundStmt(ASTContext& C, Stmt **StmtStart, unsigned numStmts, + SourceLocation LB, SourceLocation RB) + : Stmt(CompoundStmtClass), NumStmts(numStmts), LBracLoc(LB), RBracLoc(RB) { + if (NumStmts == 0) { + Body = 0; + return; + } + + Body = new (C) Stmt*[NumStmts]; + memcpy(Body, StmtStart, numStmts * sizeof(*Body)); + } + + // \brief Build an empty compound statement. + explicit CompoundStmt(EmptyShell Empty) + : Stmt(CompoundStmtClass, Empty), Body(0), NumStmts(0) { } + + void setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts); + + bool body_empty() const { return NumStmts == 0; } + unsigned size() const { return NumStmts; } + + typedef Stmt** body_iterator; + body_iterator body_begin() { return Body; } + body_iterator body_end() { return Body + NumStmts; } + Stmt *body_back() { return NumStmts ? Body[NumStmts-1] : 0; } + + typedef Stmt* const * const_body_iterator; + const_body_iterator body_begin() const { return Body; } + const_body_iterator body_end() const { return Body + NumStmts; } + const Stmt *body_back() const { return NumStmts ? Body[NumStmts-1] : 0; } + + typedef std::reverse_iterator<body_iterator> reverse_body_iterator; + reverse_body_iterator body_rbegin() { + return reverse_body_iterator(body_end()); + } + reverse_body_iterator body_rend() { + return reverse_body_iterator(body_begin()); + } + + typedef std::reverse_iterator<const_body_iterator> + const_reverse_body_iterator; + + const_reverse_body_iterator body_rbegin() const { + return const_reverse_body_iterator(body_end()); + } + + const_reverse_body_iterator body_rend() const { + return const_reverse_body_iterator(body_begin()); + } + + virtual SourceRange getSourceRange() const { + return SourceRange(LBracLoc, RBracLoc); + } + + SourceLocation getLBracLoc() const { return LBracLoc; } + void setLBracLoc(SourceLocation L) { LBracLoc = L; } + SourceLocation getRBracLoc() const { return RBracLoc; } + void setRBracLoc(SourceLocation L) { RBracLoc = L; } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CompoundStmtClass; + } + static bool classof(const CompoundStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +// SwitchCase is the base class for CaseStmt and DefaultStmt, +class SwitchCase : public Stmt { +protected: + // A pointer to the following CaseStmt or DefaultStmt class, + // used by SwitchStmt. + SwitchCase *NextSwitchCase; + + SwitchCase(StmtClass SC) : Stmt(SC), NextSwitchCase(0) {} + +public: + const SwitchCase *getNextSwitchCase() const { return NextSwitchCase; } + + SwitchCase *getNextSwitchCase() { return NextSwitchCase; } + + void setNextSwitchCase(SwitchCase *SC) { NextSwitchCase = SC; } + + Stmt *getSubStmt() { return v_getSubStmt(); } + + virtual SourceRange getSourceRange() const { return SourceRange(); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == CaseStmtClass || + T->getStmtClass() == DefaultStmtClass; + } + static bool classof(const SwitchCase *) { return true; } +protected: + virtual Stmt* v_getSubStmt() = 0; +}; + +class CaseStmt : public SwitchCase { + enum { SUBSTMT, LHS, RHS, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // The expression for the RHS is Non-null for + // GNU "case 1 ... 4" extension + SourceLocation CaseLoc; + SourceLocation EllipsisLoc; + SourceLocation ColonLoc; + + virtual Stmt* v_getSubStmt() { return getSubStmt(); } +public: + CaseStmt(Expr *lhs, Expr *rhs, SourceLocation caseLoc, + SourceLocation ellipsisLoc, SourceLocation colonLoc) + : SwitchCase(CaseStmtClass) { + SubExprs[SUBSTMT] = 0; + SubExprs[LHS] = reinterpret_cast<Stmt*>(lhs); + SubExprs[RHS] = reinterpret_cast<Stmt*>(rhs); + CaseLoc = caseLoc; + EllipsisLoc = ellipsisLoc; + ColonLoc = colonLoc; + } + + /// \brief Build an empty switch case statement. + explicit CaseStmt(EmptyShell Empty) : SwitchCase(CaseStmtClass) { } + + SourceLocation getCaseLoc() const { return CaseLoc; } + void setCaseLoc(SourceLocation L) { CaseLoc = L; } + SourceLocation getEllipsisLoc() const { return EllipsisLoc; } + void setEllipsisLoc(SourceLocation L) { EllipsisLoc = L; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + Expr *getLHS() { return reinterpret_cast<Expr*>(SubExprs[LHS]); } + Expr *getRHS() { return reinterpret_cast<Expr*>(SubExprs[RHS]); } + Stmt *getSubStmt() { return SubExprs[SUBSTMT]; } + + const Expr *getLHS() const { + return reinterpret_cast<const Expr*>(SubExprs[LHS]); + } + const Expr *getRHS() const { + return reinterpret_cast<const Expr*>(SubExprs[RHS]); + } + const Stmt *getSubStmt() const { return SubExprs[SUBSTMT]; } + + void setSubStmt(Stmt *S) { SubExprs[SUBSTMT] = S; } + void setLHS(Expr *Val) { SubExprs[LHS] = reinterpret_cast<Stmt*>(Val); } + void setRHS(Expr *Val) { SubExprs[RHS] = reinterpret_cast<Stmt*>(Val); } + + + virtual SourceRange getSourceRange() const { + // Handle deeply nested case statements with iteration instead of recursion. + const CaseStmt *CS = this; + while (const CaseStmt *CS2 = dyn_cast<CaseStmt>(CS->getSubStmt())) + CS = CS2; + + return SourceRange(CaseLoc, CS->getSubStmt()->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == CaseStmtClass; + } + static bool classof(const CaseStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +class DefaultStmt : public SwitchCase { + Stmt* SubStmt; + SourceLocation DefaultLoc; + SourceLocation ColonLoc; + virtual Stmt* v_getSubStmt() { return getSubStmt(); } +public: + DefaultStmt(SourceLocation DL, SourceLocation CL, Stmt *substmt) : + SwitchCase(DefaultStmtClass), SubStmt(substmt), DefaultLoc(DL), + ColonLoc(CL) {} + + /// \brief Build an empty default statement. + explicit DefaultStmt(EmptyShell) : SwitchCase(DefaultStmtClass) { } + + Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } + void setSubStmt(Stmt *S) { SubStmt = S; } + + SourceLocation getDefaultLoc() const { return DefaultLoc; } + void setDefaultLoc(SourceLocation L) { DefaultLoc = L; } + SourceLocation getColonLoc() const { return ColonLoc; } + void setColonLoc(SourceLocation L) { ColonLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(DefaultLoc, SubStmt->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == DefaultStmtClass; + } + static bool classof(const DefaultStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +class LabelStmt : public Stmt { + IdentifierInfo *Label; + Stmt *SubStmt; + SourceLocation IdentLoc; +public: + LabelStmt(SourceLocation IL, IdentifierInfo *label, Stmt *substmt) + : Stmt(LabelStmtClass), Label(label), + SubStmt(substmt), IdentLoc(IL) {} + + // \brief Build an empty label statement. + explicit LabelStmt(EmptyShell Empty) : Stmt(LabelStmtClass, Empty) { } + + SourceLocation getIdentLoc() const { return IdentLoc; } + IdentifierInfo *getID() const { return Label; } + void setID(IdentifierInfo *II) { Label = II; } + const char *getName() const; + Stmt *getSubStmt() { return SubStmt; } + const Stmt *getSubStmt() const { return SubStmt; } + void setIdentLoc(SourceLocation L) { IdentLoc = L; } + void setSubStmt(Stmt *SS) { SubStmt = SS; } + + virtual SourceRange getSourceRange() const { + return SourceRange(IdentLoc, SubStmt->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == LabelStmtClass; + } + static bool classof(const LabelStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// IfStmt - This represents an if/then/else. +/// +class IfStmt : public Stmt { + enum { COND, THEN, ELSE, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + + /// \brief If non-NULL, the declaration in the "if" statement. + VarDecl *Var; + + SourceLocation IfLoc; + SourceLocation ElseLoc; + +public: + IfStmt(SourceLocation IL, VarDecl *var, Expr *cond, Stmt *then, + SourceLocation EL = SourceLocation(), Stmt *elsev = 0) + : Stmt(IfStmtClass), Var(var), IfLoc(IL), ElseLoc(EL) { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[THEN] = then; + SubExprs[ELSE] = elsev; + } + + /// \brief Build an empty if/then/else statement + explicit IfStmt(EmptyShell Empty) : Stmt(IfStmtClass, Empty) { } + + /// \brief Retrieve the variable declared in this "if" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// if (int x = foo()) { + /// printf("x is %d", x); + /// } + /// \endcode + VarDecl *getConditionVariable() const { return Var; } + void setConditionVariable(VarDecl *V) { Var = V; } + + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } + const Stmt *getThen() const { return SubExprs[THEN]; } + void setThen(Stmt *S) { SubExprs[THEN] = S; } + const Stmt *getElse() const { return SubExprs[ELSE]; } + void setElse(Stmt *S) { SubExprs[ELSE] = S; } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + Stmt *getThen() { return SubExprs[THEN]; } + Stmt *getElse() { return SubExprs[ELSE]; } + + SourceLocation getIfLoc() const { return IfLoc; } + void setIfLoc(SourceLocation L) { IfLoc = L; } + SourceLocation getElseLoc() const { return ElseLoc; } + void setElseLoc(SourceLocation L) { ElseLoc = L; } + + virtual SourceRange getSourceRange() const { + if (SubExprs[ELSE]) + return SourceRange(IfLoc, SubExprs[ELSE]->getLocEnd()); + else + return SourceRange(IfLoc, SubExprs[THEN]->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IfStmtClass; + } + static bool classof(const IfStmt *) { return true; } + + // Iterators over subexpressions. The iterators will include iterating + // over the initialization expression referenced by the condition variable. + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + +protected: + virtual void DoDestroy(ASTContext &Ctx); +}; + +/// SwitchStmt - This represents a 'switch' stmt. +/// +class SwitchStmt : public Stmt { + enum { COND, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + VarDecl *Var; + // This points to a linked list of case and default statements. + SwitchCase *FirstCase; + SourceLocation SwitchLoc; + +protected: + virtual void DoDestroy(ASTContext &Ctx); + +public: + SwitchStmt(VarDecl *Var, Expr *cond) + : Stmt(SwitchStmtClass), Var(Var), FirstCase(0) + { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = NULL; + } + + /// \brief Build a empty switch statement. + explicit SwitchStmt(EmptyShell Empty) : Stmt(SwitchStmtClass, Empty) { } + + /// \brief Retrieve the variable declared in this "switch" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// switch (int x = foo()) { + /// case 0: break; + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const { return Var; } + void setConditionVariable(VarDecl *V) { Var = V; } + + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + const Stmt *getBody() const { return SubExprs[BODY]; } + const SwitchCase *getSwitchCaseList() const { return FirstCase; } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt *>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + SwitchCase *getSwitchCaseList() { return FirstCase; } + + /// \brief Set the case list for this switch statement. + /// + /// The caller is responsible for incrementing the retain counts on + /// all of the SwitchCase statements in this list. + void setSwitchCaseList(SwitchCase *SC) { FirstCase = SC; } + + SourceLocation getSwitchLoc() const { return SwitchLoc; } + void setSwitchLoc(SourceLocation L) { SwitchLoc = L; } + + void setBody(Stmt *S, SourceLocation SL) { + SubExprs[BODY] = S; + SwitchLoc = SL; + } + void addSwitchCase(SwitchCase *SC) { + assert(!SC->getNextSwitchCase() && "case/default already added to a switch"); + SC->Retain(); + SC->setNextSwitchCase(FirstCase); + FirstCase = SC; + } + virtual SourceRange getSourceRange() const { + return SourceRange(SwitchLoc, SubExprs[BODY]->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == SwitchStmtClass; + } + static bool classof(const SwitchStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// WhileStmt - This represents a 'while' stmt. +/// +class WhileStmt : public Stmt { + enum { COND, BODY, END_EXPR }; + VarDecl *Var; + Stmt* SubExprs[END_EXPR]; + SourceLocation WhileLoc; +public: + WhileStmt(VarDecl *Var, Expr *cond, Stmt *body, SourceLocation WL) + : Stmt(WhileStmtClass), Var(Var) + { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = body; + WhileLoc = WL; + } + + /// \brief Build an empty while statement. + explicit WhileStmt(EmptyShell Empty) : Stmt(WhileStmtClass, Empty) { } + + /// \brief Retrieve the variable declared in this "while" statement, if any. + /// + /// In the following example, "x" is the condition variable. + /// \code + /// while (int x = random()) { + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const { return Var; } + void setConditionVariable(VarDecl *V) { Var = V; } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + const Stmt *getBody() const { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getWhileLoc() const { return WhileLoc; } + void setWhileLoc(SourceLocation L) { WhileLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(WhileLoc, SubExprs[BODY]->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == WhileStmtClass; + } + static bool classof(const WhileStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + +protected: + virtual void DoDestroy(ASTContext &Ctx); +}; + +/// DoStmt - This represents a 'do/while' stmt. +/// +class DoStmt : public Stmt { + enum { COND, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; + SourceLocation DoLoc; + SourceLocation WhileLoc; + SourceLocation RParenLoc; // Location of final ')' in do stmt condition. + +public: + DoStmt(Stmt *body, Expr *cond, SourceLocation DL, SourceLocation WL, + SourceLocation RP) + : Stmt(DoStmtClass), DoLoc(DL), WhileLoc(WL), RParenLoc(RP) { + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = body; + } + + /// \brief Build an empty do-while statement. + explicit DoStmt(EmptyShell Empty) : Stmt(DoStmtClass, Empty) { } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + Stmt *getBody() { return SubExprs[BODY]; } + const Stmt *getBody() const { return SubExprs[BODY]; } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getDoLoc() const { return DoLoc; } + void setDoLoc(SourceLocation L) { DoLoc = L; } + SourceLocation getWhileLoc() const { return WhileLoc; } + void setWhileLoc(SourceLocation L) { WhileLoc = L; } + + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(DoLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == DoStmtClass; + } + static bool classof(const DoStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// ForStmt - This represents a 'for (init;cond;inc)' stmt. Note that any of +/// the init/cond/inc parts of the ForStmt will be null if they were not +/// specified in the source. +/// +class ForStmt : public Stmt { + enum { INIT, COND, INC, BODY, END_EXPR }; + Stmt* SubExprs[END_EXPR]; // SubExprs[INIT] is an expression or declstmt. + VarDecl *CondVar; + SourceLocation ForLoc; + SourceLocation LParenLoc, RParenLoc; + +public: + ForStmt(Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc, Stmt *Body, + SourceLocation FL, SourceLocation LP, SourceLocation RP) + : Stmt(ForStmtClass), CondVar(condVar), ForLoc(FL), LParenLoc(LP), + RParenLoc(RP) + { + SubExprs[INIT] = Init; + SubExprs[COND] = reinterpret_cast<Stmt*>(Cond); + SubExprs[INC] = reinterpret_cast<Stmt*>(Inc); + SubExprs[BODY] = Body; + } + + /// \brief Build an empty for statement. + explicit ForStmt(EmptyShell Empty) : Stmt(ForStmtClass, Empty) { } + + Stmt *getInit() { return SubExprs[INIT]; } + + /// \brief Retrieve the variable declared in this "for" statement, if any. + /// + /// In the following example, "y" is the condition variable. + /// \code + /// for (int x = random(); int y = mangle(x); ++x) { + /// // ... + /// } + /// \endcode + VarDecl *getConditionVariable() const { return CondVar; } + void setConditionVariable(VarDecl *V) { CondVar = V; } + + Expr *getCond() { return reinterpret_cast<Expr*>(SubExprs[COND]); } + Expr *getInc() { return reinterpret_cast<Expr*>(SubExprs[INC]); } + Stmt *getBody() { return SubExprs[BODY]; } + + const Stmt *getInit() const { return SubExprs[INIT]; } + const Expr *getCond() const { return reinterpret_cast<Expr*>(SubExprs[COND]);} + const Expr *getInc() const { return reinterpret_cast<Expr*>(SubExprs[INC]); } + const Stmt *getBody() const { return SubExprs[BODY]; } + + void setInit(Stmt *S) { SubExprs[INIT] = S; } + void setCond(Expr *E) { SubExprs[COND] = reinterpret_cast<Stmt*>(E); } + void setInc(Expr *E) { SubExprs[INC] = reinterpret_cast<Stmt*>(E); } + void setBody(Stmt *S) { SubExprs[BODY] = S; } + + SourceLocation getForLoc() const { return ForLoc; } + void setForLoc(SourceLocation L) { ForLoc = L; } + SourceLocation getLParenLoc() const { return LParenLoc; } + void setLParenLoc(SourceLocation L) { LParenLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(ForLoc, SubExprs[BODY]->getLocEnd()); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ForStmtClass; + } + static bool classof(const ForStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); + +protected: + virtual void DoDestroy(ASTContext &Ctx); +}; + +/// GotoStmt - This represents a direct goto. +/// +class GotoStmt : public Stmt { + LabelStmt *Label; + SourceLocation GotoLoc; + SourceLocation LabelLoc; +public: + GotoStmt(LabelStmt *label, SourceLocation GL, SourceLocation LL) + : Stmt(GotoStmtClass), Label(label), GotoLoc(GL), LabelLoc(LL) {} + + /// \brief Build an empty goto statement. + explicit GotoStmt(EmptyShell Empty) : Stmt(GotoStmtClass, Empty) { } + + LabelStmt *getLabel() const { return Label; } + void setLabel(LabelStmt *S) { Label = S; } + + SourceLocation getGotoLoc() const { return GotoLoc; } + void setGotoLoc(SourceLocation L) { GotoLoc = L; } + SourceLocation getLabelLoc() const { return LabelLoc; } + void setLabelLoc(SourceLocation L) { LabelLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(GotoLoc, LabelLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == GotoStmtClass; + } + static bool classof(const GotoStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// IndirectGotoStmt - This represents an indirect goto. +/// +class IndirectGotoStmt : public Stmt { + SourceLocation GotoLoc; + SourceLocation StarLoc; + Stmt *Target; +public: + IndirectGotoStmt(SourceLocation gotoLoc, SourceLocation starLoc, + Expr *target) + : Stmt(IndirectGotoStmtClass), GotoLoc(gotoLoc), StarLoc(starLoc), + Target((Stmt*)target) {} + + /// \brief Build an empty indirect goto statement. + explicit IndirectGotoStmt(EmptyShell Empty) + : Stmt(IndirectGotoStmtClass, Empty) { } + + void setGotoLoc(SourceLocation L) { GotoLoc = L; } + SourceLocation getGotoLoc() const { return GotoLoc; } + void setStarLoc(SourceLocation L) { StarLoc = L; } + SourceLocation getStarLoc() const { return StarLoc; } + + Expr *getTarget(); + const Expr *getTarget() const; + void setTarget(Expr *E) { Target = reinterpret_cast<Stmt*>(E); } + + virtual SourceRange getSourceRange() const { + return SourceRange(GotoLoc, Target->getLocEnd()); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == IndirectGotoStmtClass; + } + static bool classof(const IndirectGotoStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// ContinueStmt - This represents a continue. +/// +class ContinueStmt : public Stmt { + SourceLocation ContinueLoc; +public: + ContinueStmt(SourceLocation CL) : Stmt(ContinueStmtClass), ContinueLoc(CL) {} + + /// \brief Build an empty continue statement. + explicit ContinueStmt(EmptyShell Empty) : Stmt(ContinueStmtClass, Empty) { } + + SourceLocation getContinueLoc() const { return ContinueLoc; } + void setContinueLoc(SourceLocation L) { ContinueLoc = L; } + + virtual SourceRange getSourceRange() const { + return SourceRange(ContinueLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ContinueStmtClass; + } + static bool classof(const ContinueStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// BreakStmt - This represents a break. +/// +class BreakStmt : public Stmt { + SourceLocation BreakLoc; +public: + BreakStmt(SourceLocation BL) : Stmt(BreakStmtClass), BreakLoc(BL) {} + + /// \brief Build an empty break statement. + explicit BreakStmt(EmptyShell Empty) : Stmt(BreakStmtClass, Empty) { } + + SourceLocation getBreakLoc() const { return BreakLoc; } + void setBreakLoc(SourceLocation L) { BreakLoc = L; } + + virtual SourceRange getSourceRange() const { return SourceRange(BreakLoc); } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == BreakStmtClass; + } + static bool classof(const BreakStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + + +/// ReturnStmt - This represents a return, optionally of an expression: +/// return; +/// return 4; +/// +/// Note that GCC allows return with no argument in a function declared to +/// return a value, and it allows returning a value in functions declared to +/// return void. We explicitly model this in the AST, which means you can't +/// depend on the return type of the function and the presence of an argument. +/// +class ReturnStmt : public Stmt { + Stmt *RetExpr; + SourceLocation RetLoc; + const VarDecl *NRVOCandidate; + +public: + ReturnStmt(SourceLocation RL) + : Stmt(ReturnStmtClass), RetExpr(0), RetLoc(RL), NRVOCandidate(0) { } + + ReturnStmt(SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate) + : Stmt(ReturnStmtClass), RetExpr((Stmt*) E), RetLoc(RL), + NRVOCandidate(NRVOCandidate) {} + + /// \brief Build an empty return expression. + explicit ReturnStmt(EmptyShell Empty) : Stmt(ReturnStmtClass, Empty) { } + + const Expr *getRetValue() const; + Expr *getRetValue(); + void setRetValue(Expr *E) { RetExpr = reinterpret_cast<Stmt*>(E); } + + SourceLocation getReturnLoc() const { return RetLoc; } + void setReturnLoc(SourceLocation L) { RetLoc = L; } + + /// \brief Retrieve the variable that might be used for the named return + /// value optimization. + /// + /// The optimization itself can only be performed if the variable is + /// also marked as an NRVO object. + const VarDecl *getNRVOCandidate() const { return NRVOCandidate; } + void setNRVOCandidate(const VarDecl *Var) { NRVOCandidate = Var; } + + virtual SourceRange getSourceRange() const; + + static bool classof(const Stmt *T) { + return T->getStmtClass() == ReturnStmtClass; + } + static bool classof(const ReturnStmt *) { return true; } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +/// AsmStmt - This represents a GNU inline-assembly statement extension. +/// +class AsmStmt : public Stmt { + SourceLocation AsmLoc, RParenLoc; + StringLiteral *AsmStr; + + bool IsSimple; + bool IsVolatile; + bool MSAsm; + + unsigned NumOutputs; + unsigned NumInputs; + unsigned NumClobbers; + + // FIXME: If we wanted to, we could allocate all of these in one big array. + IdentifierInfo **Names; + StringLiteral **Constraints; + Stmt **Exprs; + StringLiteral **Clobbers; + +protected: + virtual void DoDestroy(ASTContext &Ctx); + +public: + AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, bool isvolatile, + bool msasm, unsigned numoutputs, unsigned numinputs, + IdentifierInfo **names, StringLiteral **constraints, + Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, + StringLiteral **clobbers, SourceLocation rparenloc); + + /// \brief Build an empty inline-assembly statement. + explicit AsmStmt(EmptyShell Empty) : Stmt(AsmStmtClass, Empty), + Names(0), Constraints(0), Exprs(0), Clobbers(0) { } + + SourceLocation getAsmLoc() const { return AsmLoc; } + void setAsmLoc(SourceLocation L) { AsmLoc = L; } + SourceLocation getRParenLoc() const { return RParenLoc; } + void setRParenLoc(SourceLocation L) { RParenLoc = L; } + + bool isVolatile() const { return IsVolatile; } + void setVolatile(bool V) { IsVolatile = V; } + bool isSimple() const { return IsSimple; } + void setSimple(bool V) { IsSimple = V; } + bool isMSAsm() const { return MSAsm; } + void setMSAsm(bool V) { MSAsm = V; } + + //===--- Asm String Analysis ---===// + + const StringLiteral *getAsmString() const { return AsmStr; } + StringLiteral *getAsmString() { return AsmStr; } + void setAsmString(StringLiteral *E) { AsmStr = E; } + + /// AsmStringPiece - this is part of a decomposed asm string specification + /// (for use with the AnalyzeAsmString function below). An asm string is + /// considered to be a concatenation of these parts. + class AsmStringPiece { + public: + enum Kind { + String, // String in .ll asm string form, "$" -> "$$" and "%%" -> "%". + Operand // Operand reference, with optional modifier %c4. + }; + private: + Kind MyKind; + std::string Str; + unsigned OperandNo; + public: + AsmStringPiece(const std::string &S) : MyKind(String), Str(S) {} + AsmStringPiece(unsigned OpNo, char Modifier) + : MyKind(Operand), Str(), OperandNo(OpNo) { + Str += Modifier; + } + + bool isString() const { return MyKind == String; } + bool isOperand() const { return MyKind == Operand; } + + const std::string &getString() const { + assert(isString()); + return Str; + } + + unsigned getOperandNo() const { + assert(isOperand()); + return OperandNo; + } + + /// getModifier - Get the modifier for this operand, if present. This + /// returns '\0' if there was no modifier. + char getModifier() const { + assert(isOperand()); + return Str[0]; + } + }; + + /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing + /// it into pieces. If the asm string is erroneous, emit errors and return + /// true, otherwise return false. This handles canonicalization and + /// translation of strings from GCC syntax to LLVM IR syntax, and handles + //// flattening of named references like %[foo] to Operand AsmStringPiece's. + unsigned AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece> &Pieces, + ASTContext &C, unsigned &DiagOffs) const; + + + //===--- Output operands ---===// + + unsigned getNumOutputs() const { return NumOutputs; } + + IdentifierInfo *getOutputIdentifier(unsigned i) const { + return Names[i]; + } + + llvm::StringRef getOutputName(unsigned i) const { + if (IdentifierInfo *II = getOutputIdentifier(i)) + return II->getName(); + + return llvm::StringRef(); + } + + /// getOutputConstraint - Return the constraint string for the specified + /// output operand. All output constraints are known to be non-empty (either + /// '=' or '+'). + llvm::StringRef getOutputConstraint(unsigned i) const; + + const StringLiteral *getOutputConstraintLiteral(unsigned i) const { + return Constraints[i]; + } + StringLiteral *getOutputConstraintLiteral(unsigned i) { + return Constraints[i]; + } + + Expr *getOutputExpr(unsigned i); + + const Expr *getOutputExpr(unsigned i) const { + return const_cast<AsmStmt*>(this)->getOutputExpr(i); + } + + /// isOutputPlusConstraint - Return true if the specified output constraint + /// is a "+" constraint (which is both an input and an output) or false if it + /// is an "=" constraint (just an output). + bool isOutputPlusConstraint(unsigned i) const { + return getOutputConstraint(i)[0] == '+'; + } + + /// getNumPlusOperands - Return the number of output operands that have a "+" + /// constraint. + unsigned getNumPlusOperands() const; + + //===--- Input operands ---===// + + unsigned getNumInputs() const { return NumInputs; } + + IdentifierInfo *getInputIdentifier(unsigned i) const { + return Names[i + NumOutputs]; + } + + llvm::StringRef getInputName(unsigned i) const { + if (IdentifierInfo *II = getInputIdentifier(i)) + return II->getName(); + + return llvm::StringRef(); + } + + /// getInputConstraint - Return the specified input constraint. Unlike output + /// constraints, these can be empty. + llvm::StringRef getInputConstraint(unsigned i) const; + + const StringLiteral *getInputConstraintLiteral(unsigned i) const { + return Constraints[i + NumOutputs]; + } + StringLiteral *getInputConstraintLiteral(unsigned i) { + return Constraints[i + NumOutputs]; + } + + Expr *getInputExpr(unsigned i); + + const Expr *getInputExpr(unsigned i) const { + return const_cast<AsmStmt*>(this)->getInputExpr(i); + } + + void setOutputsAndInputsAndClobbers(ASTContext &C, + IdentifierInfo **Names, + StringLiteral **Constraints, + Stmt **Exprs, + unsigned NumOutputs, + unsigned NumInputs, + StringLiteral **Clobbers, + unsigned NumClobbers); + + //===--- Other ---===// + + /// getNamedOperand - Given a symbolic operand reference like %[foo], + /// translate this into a numeric value needed to reference the same operand. + /// This returns -1 if the operand name is invalid. + int getNamedOperand(llvm::StringRef SymbolicName) const; + + unsigned getNumClobbers() const { return NumClobbers; } + StringLiteral *getClobber(unsigned i) { return Clobbers[i]; } + const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; } + + virtual SourceRange getSourceRange() const { + return SourceRange(AsmLoc, RParenLoc); + } + + static bool classof(const Stmt *T) {return T->getStmtClass() == AsmStmtClass;} + static bool classof(const AsmStmt *) { return true; } + + // Input expr iterators. + + typedef ExprIterator inputs_iterator; + typedef ConstExprIterator const_inputs_iterator; + + inputs_iterator begin_inputs() { + return &Exprs[0] + NumOutputs; + } + + inputs_iterator end_inputs() { + return &Exprs[0] + NumOutputs + NumInputs; + } + + const_inputs_iterator begin_inputs() const { + return &Exprs[0] + NumOutputs; + } + + const_inputs_iterator end_inputs() const { + return &Exprs[0] + NumOutputs + NumInputs; + } + + // Output expr iterators. + + typedef ExprIterator outputs_iterator; + typedef ConstExprIterator const_outputs_iterator; + + outputs_iterator begin_outputs() { + return &Exprs[0]; + } + outputs_iterator end_outputs() { + return &Exprs[0] + NumOutputs; + } + + const_outputs_iterator begin_outputs() const { + return &Exprs[0]; + } + const_outputs_iterator end_outputs() const { + return &Exprs[0] + NumOutputs; + } + + // Child iterators + + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + +} // end namespace clang + +#endif |