diff options
Diffstat (limited to 'lib/AST/Expr.cpp')
-rw-r--r-- | lib/AST/Expr.cpp | 2059 |
1 files changed, 2059 insertions, 0 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp new file mode 100644 index 0000000..4a53a41 --- /dev/null +++ b/lib/AST/Expr.cpp @@ -0,0 +1,2059 @@ +//===--- Expr.cpp - Expression AST Node Implementation --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Expr class and subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Expr.h" +#include "clang/AST/APValue.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/TargetInfo.h" +#include <algorithm> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Primary Expressions. +//===----------------------------------------------------------------------===// + +PredefinedExpr* PredefinedExpr::Clone(ASTContext &C) const { + return new (C) PredefinedExpr(Loc, getType(), Type); +} + +IntegerLiteral* IntegerLiteral::Clone(ASTContext &C) const { + return new (C) IntegerLiteral(Value, getType(), Loc); +} + +CharacterLiteral* CharacterLiteral::Clone(ASTContext &C) const { + return new (C) CharacterLiteral(Value, IsWide, getType(), Loc); +} + +FloatingLiteral* FloatingLiteral::Clone(ASTContext &C) const { + bool exact = IsExact; + return new (C) FloatingLiteral(Value, &exact, getType(), Loc); +} + +ImaginaryLiteral* ImaginaryLiteral::Clone(ASTContext &C) const { + // FIXME: Use virtual Clone(), once it is available + Expr *ClonedVal = 0; + if (const IntegerLiteral *IntLit = dyn_cast<IntegerLiteral>(Val)) + ClonedVal = IntLit->Clone(C); + else + ClonedVal = cast<FloatingLiteral>(Val)->Clone(C); + return new (C) ImaginaryLiteral(ClonedVal, getType()); +} + +GNUNullExpr* GNUNullExpr::Clone(ASTContext &C) const { + return new (C) GNUNullExpr(getType(), TokenLoc); +} + +/// getValueAsApproximateDouble - This returns the value as an inaccurate +/// double. Note that this may cause loss of precision, but is useful for +/// debugging dumps, etc. +double FloatingLiteral::getValueAsApproximateDouble() const { + llvm::APFloat V = getValue(); + bool ignored; + V.convert(llvm::APFloat::IEEEdouble, llvm::APFloat::rmNearestTiesToEven, + &ignored); + return V.convertToDouble(); +} + +StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, + unsigned ByteLength, bool Wide, + QualType Ty, + const SourceLocation *Loc, + unsigned NumStrs) { + // Allocate enough space for the StringLiteral plus an array of locations for + // any concatenated string tokens. + void *Mem = C.Allocate(sizeof(StringLiteral)+ + sizeof(SourceLocation)*(NumStrs-1), + llvm::alignof<StringLiteral>()); + StringLiteral *SL = new (Mem) StringLiteral(Ty); + + // OPTIMIZE: could allocate this appended to the StringLiteral. + char *AStrData = new (C, 1) char[ByteLength]; + memcpy(AStrData, StrData, ByteLength); + SL->StrData = AStrData; + SL->ByteLength = ByteLength; + SL->IsWide = Wide; + SL->TokLocs[0] = Loc[0]; + SL->NumConcatenated = NumStrs; + + if (NumStrs != 1) + memcpy(&SL->TokLocs[1], Loc+1, sizeof(SourceLocation)*(NumStrs-1)); + return SL; +} + +StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) { + void *Mem = C.Allocate(sizeof(StringLiteral)+ + sizeof(SourceLocation)*(NumStrs-1), + llvm::alignof<StringLiteral>()); + StringLiteral *SL = new (Mem) StringLiteral(QualType()); + SL->StrData = 0; + SL->ByteLength = 0; + SL->NumConcatenated = NumStrs; + return SL; +} + +StringLiteral* StringLiteral::Clone(ASTContext &C) const { + return Create(C, StrData, ByteLength, IsWide, getType(), + TokLocs, NumConcatenated); +} + +void StringLiteral::Destroy(ASTContext &C) { + C.Deallocate(const_cast<char*>(StrData)); + this->~StringLiteral(); + C.Deallocate(this); +} + +void StringLiteral::setStrData(ASTContext &C, const char *Str, unsigned Len) { + if (StrData) + C.Deallocate(const_cast<char*>(StrData)); + + char *AStrData = new (C, 1) char[Len]; + memcpy(AStrData, Str, Len); + StrData = AStrData; + ByteLength = Len; +} + +/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it +/// corresponds to, e.g. "sizeof" or "[pre]++". +const char *UnaryOperator::getOpcodeStr(Opcode Op) { + switch (Op) { + default: assert(0 && "Unknown unary operator"); + case PostInc: return "++"; + case PostDec: return "--"; + case PreInc: return "++"; + case PreDec: return "--"; + case AddrOf: return "&"; + case Deref: return "*"; + case Plus: return "+"; + case Minus: return "-"; + case Not: return "~"; + case LNot: return "!"; + case Real: return "__real"; + case Imag: return "__imag"; + case Extension: return "__extension__"; + case OffsetOf: return "__builtin_offsetof"; + } +} + +UnaryOperator::Opcode +UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) { + switch (OO) { + default: assert(false && "No unary operator for overloaded function"); + case OO_PlusPlus: return Postfix ? PostInc : PreInc; + case OO_MinusMinus: return Postfix ? PostDec : PreDec; + case OO_Amp: return AddrOf; + case OO_Star: return Deref; + case OO_Plus: return Plus; + case OO_Minus: return Minus; + case OO_Tilde: return Not; + case OO_Exclaim: return LNot; + } +} + +OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { + switch (Opc) { + case PostInc: case PreInc: return OO_PlusPlus; + case PostDec: case PreDec: return OO_MinusMinus; + case AddrOf: return OO_Amp; + case Deref: return OO_Star; + case Plus: return OO_Plus; + case Minus: return OO_Minus; + case Not: return OO_Tilde; + case LNot: return OO_Exclaim; + default: return OO_None; + } +} + + +//===----------------------------------------------------------------------===// +// Postfix Operators. +//===----------------------------------------------------------------------===// + +CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, Expr **args, + unsigned numargs, QualType t, SourceLocation rparenloc) + : Expr(SC, t, + fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs), + fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)), + NumArgs(numargs) { + + SubExprs = new (C) Stmt*[numargs+1]; + SubExprs[FN] = fn; + for (unsigned i = 0; i != numargs; ++i) + SubExprs[i+ARGS_START] = args[i]; + + RParenLoc = rparenloc; +} + +CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, + QualType t, SourceLocation rparenloc) + : Expr(CallExprClass, t, + fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs), + fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)), + NumArgs(numargs) { + + SubExprs = new (C) Stmt*[numargs+1]; + SubExprs[FN] = fn; + for (unsigned i = 0; i != numargs; ++i) + SubExprs[i+ARGS_START] = args[i]; + + RParenLoc = rparenloc; +} + +CallExpr::CallExpr(ASTContext &C, EmptyShell Empty) + : Expr(CallExprClass, Empty), SubExprs(0), NumArgs(0) { + SubExprs = new (C) Stmt*[1]; +} + +void CallExpr::Destroy(ASTContext& C) { + DestroyChildren(C); + if (SubExprs) C.Deallocate(SubExprs); + this->~CallExpr(); + C.Deallocate(this); +} + +/// setNumArgs - This changes the number of arguments present in this call. +/// Any orphaned expressions are deleted by this, and any new operands are set +/// to null. +void CallExpr::setNumArgs(ASTContext& C, unsigned NumArgs) { + // No change, just return. + if (NumArgs == getNumArgs()) return; + + // If shrinking # arguments, just delete the extras and forgot them. + if (NumArgs < getNumArgs()) { + for (unsigned i = NumArgs, e = getNumArgs(); i != e; ++i) + getArg(i)->Destroy(C); + this->NumArgs = NumArgs; + return; + } + + // Otherwise, we are growing the # arguments. New an bigger argument array. + Stmt **NewSubExprs = new Stmt*[NumArgs+1]; + // Copy over args. + for (unsigned i = 0; i != getNumArgs()+ARGS_START; ++i) + NewSubExprs[i] = SubExprs[i]; + // Null out new args. + for (unsigned i = getNumArgs()+ARGS_START; i != NumArgs+ARGS_START; ++i) + NewSubExprs[i] = 0; + + if (SubExprs) C.Deallocate(SubExprs); + SubExprs = NewSubExprs; + this->NumArgs = NumArgs; +} + +/// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If +/// not, return 0. +unsigned CallExpr::isBuiltinCall(ASTContext &Context) const { + // All simple function calls (e.g. func()) are implicitly cast to pointer to + // function. As a result, we try and obtain the DeclRefExpr from the + // ImplicitCastExpr. + const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(getCallee()); + if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). + return 0; + + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr()); + if (!DRE) + return 0; + + const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()); + if (!FDecl) + return 0; + + if (!FDecl->getIdentifier()) + return 0; + + return FDecl->getBuiltinID(Context); +} + +QualType CallExpr::getCallReturnType() const { + QualType CalleeType = getCallee()->getType(); + if (const PointerType *FnTypePtr = CalleeType->getAsPointerType()) + CalleeType = FnTypePtr->getPointeeType(); + else if (const BlockPointerType *BPT = CalleeType->getAsBlockPointerType()) + CalleeType = BPT->getPointeeType(); + + const FunctionType *FnType = CalleeType->getAsFunctionType(); + return FnType->getResultType(); +} + +/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it +/// corresponds to, e.g. "<<=". +const char *BinaryOperator::getOpcodeStr(Opcode Op) { + switch (Op) { + case PtrMemD: return ".*"; + case PtrMemI: return "->*"; + case Mul: return "*"; + case Div: return "/"; + case Rem: return "%"; + case Add: return "+"; + case Sub: return "-"; + case Shl: return "<<"; + case Shr: return ">>"; + case LT: return "<"; + case GT: return ">"; + case LE: return "<="; + case GE: return ">="; + case EQ: return "=="; + case NE: return "!="; + case And: return "&"; + case Xor: return "^"; + case Or: return "|"; + case LAnd: return "&&"; + case LOr: return "||"; + case Assign: return "="; + case MulAssign: return "*="; + case DivAssign: return "/="; + case RemAssign: return "%="; + case AddAssign: return "+="; + case SubAssign: return "-="; + case ShlAssign: return "<<="; + case ShrAssign: return ">>="; + case AndAssign: return "&="; + case XorAssign: return "^="; + case OrAssign: return "|="; + case Comma: return ","; + } + + return ""; +} + +BinaryOperator::Opcode +BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) { + switch (OO) { + default: assert(false && "Not an overloadable binary operator"); + case OO_Plus: return Add; + case OO_Minus: return Sub; + case OO_Star: return Mul; + case OO_Slash: return Div; + case OO_Percent: return Rem; + case OO_Caret: return Xor; + case OO_Amp: return And; + case OO_Pipe: return Or; + case OO_Equal: return Assign; + case OO_Less: return LT; + case OO_Greater: return GT; + case OO_PlusEqual: return AddAssign; + case OO_MinusEqual: return SubAssign; + case OO_StarEqual: return MulAssign; + case OO_SlashEqual: return DivAssign; + case OO_PercentEqual: return RemAssign; + case OO_CaretEqual: return XorAssign; + case OO_AmpEqual: return AndAssign; + case OO_PipeEqual: return OrAssign; + case OO_LessLess: return Shl; + case OO_GreaterGreater: return Shr; + case OO_LessLessEqual: return ShlAssign; + case OO_GreaterGreaterEqual: return ShrAssign; + case OO_EqualEqual: return EQ; + case OO_ExclaimEqual: return NE; + case OO_LessEqual: return LE; + case OO_GreaterEqual: return GE; + case OO_AmpAmp: return LAnd; + case OO_PipePipe: return LOr; + case OO_Comma: return Comma; + case OO_ArrowStar: return PtrMemI; + } +} + +OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { + static const OverloadedOperatorKind OverOps[] = { + /* .* Cannot be overloaded */OO_None, OO_ArrowStar, + OO_Star, OO_Slash, OO_Percent, + OO_Plus, OO_Minus, + OO_LessLess, OO_GreaterGreater, + OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual, + OO_EqualEqual, OO_ExclaimEqual, + OO_Amp, + OO_Caret, + OO_Pipe, + OO_AmpAmp, + OO_PipePipe, + OO_Equal, OO_StarEqual, + OO_SlashEqual, OO_PercentEqual, + OO_PlusEqual, OO_MinusEqual, + OO_LessLessEqual, OO_GreaterGreaterEqual, + OO_AmpEqual, OO_CaretEqual, + OO_PipeEqual, + OO_Comma + }; + return OverOps[Opc]; +} + +InitListExpr::InitListExpr(SourceLocation lbraceloc, + Expr **initExprs, unsigned numInits, + SourceLocation rbraceloc) + : Expr(InitListExprClass, QualType(), + hasAnyTypeDependentArguments(initExprs, numInits), + hasAnyValueDependentArguments(initExprs, numInits)), + LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), + UnionFieldInit(0), HadArrayRangeDesignator(false) { + + InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits); +} + +void InitListExpr::reserveInits(unsigned NumInits) { + if (NumInits > InitExprs.size()) + InitExprs.reserve(NumInits); +} + +void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) { + for (unsigned Idx = NumInits, LastIdx = InitExprs.size(); + Idx < LastIdx; ++Idx) + InitExprs[Idx]->Destroy(Context); + InitExprs.resize(NumInits, 0); +} + +Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) { + if (Init >= InitExprs.size()) { + InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0); + InitExprs.back() = expr; + return 0; + } + + Expr *Result = cast_or_null<Expr>(InitExprs[Init]); + InitExprs[Init] = expr; + return Result; +} + +/// getFunctionType - Return the underlying function type for this block. +/// +const FunctionType *BlockExpr::getFunctionType() const { + return getType()->getAsBlockPointerType()-> + getPointeeType()->getAsFunctionType(); +} + +SourceLocation BlockExpr::getCaretLocation() const { + return TheBlock->getCaretLocation(); +} +const Stmt *BlockExpr::getBody() const { + return TheBlock->getBody(); +} +Stmt *BlockExpr::getBody() { + return TheBlock->getBody(); +} + + +//===----------------------------------------------------------------------===// +// Generic Expression Routines +//===----------------------------------------------------------------------===// + +/// isUnusedResultAWarning - Return true if this immediate expression should +/// be warned about if the result is unused. If so, fill in Loc and Ranges +/// with location to warn on and the source range[s] to report with the +/// warning. +bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, + SourceRange &R2) const { + // Don't warn if the expr is type dependent. The type could end up + // instantiating to void. + if (isTypeDependent()) + return false; + + switch (getStmtClass()) { + default: + Loc = getExprLoc(); + R1 = getSourceRange(); + return true; + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()-> + isUnusedResultAWarning(Loc, R1, R2); + case UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(this); + + switch (UO->getOpcode()) { + default: break; + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: // ++/-- + return false; // Not a warning. + case UnaryOperator::Deref: + // Dereferencing a volatile pointer is a side-effect. + if (getType().isVolatileQualified()) + return false; + break; + case UnaryOperator::Real: + case UnaryOperator::Imag: + // accessing a piece of a volatile complex is a side-effect. + if (UO->getSubExpr()->getType().isVolatileQualified()) + return false; + break; + case UnaryOperator::Extension: + return UO->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + } + Loc = UO->getOperatorLoc(); + R1 = UO->getSubExpr()->getSourceRange(); + return true; + } + case BinaryOperatorClass: { + const BinaryOperator *BO = cast<BinaryOperator>(this); + // Consider comma to have side effects if the LHS or RHS does. + if (BO->getOpcode() == BinaryOperator::Comma) + return BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2) || + BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2); + + if (BO->isAssignmentOp()) + return false; + Loc = BO->getOperatorLoc(); + R1 = BO->getLHS()->getSourceRange(); + R2 = BO->getRHS()->getSourceRange(); + return true; + } + case CompoundAssignOperatorClass: + return false; + + case ConditionalOperatorClass: { + // The condition must be evaluated, but if either the LHS or RHS is a + // warning, warn about them. + const ConditionalOperator *Exp = cast<ConditionalOperator>(this); + if (Exp->getLHS() && Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2)) + return true; + return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2); + } + + case MemberExprClass: + // If the base pointer or element is to a volatile pointer/field, accessing + // it is a side effect. + if (getType().isVolatileQualified()) + return false; + Loc = cast<MemberExpr>(this)->getMemberLoc(); + R1 = SourceRange(Loc, Loc); + R2 = cast<MemberExpr>(this)->getBase()->getSourceRange(); + return true; + + case ArraySubscriptExprClass: + // If the base pointer or element is to a volatile pointer/field, accessing + // it is a side effect. + if (getType().isVolatileQualified()) + return false; + Loc = cast<ArraySubscriptExpr>(this)->getRBracketLoc(); + R1 = cast<ArraySubscriptExpr>(this)->getLHS()->getSourceRange(); + R2 = cast<ArraySubscriptExpr>(this)->getRHS()->getSourceRange(); + return true; + + case CallExprClass: + case CXXOperatorCallExprClass: + case CXXMemberCallExprClass: { + // If this is a direct call, get the callee. + const CallExpr *CE = cast<CallExpr>(this); + const Expr *CalleeExpr = CE->getCallee()->IgnoreParenCasts(); + if (const DeclRefExpr *CalleeDRE = dyn_cast<DeclRefExpr>(CalleeExpr)) { + // If the callee has attribute pure, const, or warn_unused_result, warn + // about it. void foo() { strlen("bar"); } should warn. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeDRE->getDecl())) + if (FD->getAttr<WarnUnusedResultAttr>() || + FD->getAttr<PureAttr>() || FD->getAttr<ConstAttr>()) { + Loc = CE->getCallee()->getLocStart(); + R1 = CE->getCallee()->getSourceRange(); + + if (unsigned NumArgs = CE->getNumArgs()) + R2 = SourceRange(CE->getArg(0)->getLocStart(), + CE->getArg(NumArgs-1)->getLocEnd()); + return true; + } + } + return false; + } + case ObjCMessageExprClass: + return false; + case StmtExprClass: { + // Statement exprs don't logically have side effects themselves, but are + // sometimes used in macros in ways that give them a type that is unused. + // For example ({ blah; foo(); }) will end up with a type if foo has a type. + // however, if the result of the stmt expr is dead, we don't want to emit a + // warning. + const CompoundStmt *CS = cast<StmtExpr>(this)->getSubStmt(); + if (!CS->body_empty()) + if (const Expr *E = dyn_cast<Expr>(CS->body_back())) + return E->isUnusedResultAWarning(Loc, R1, R2); + + Loc = cast<StmtExpr>(this)->getLParenLoc(); + R1 = getSourceRange(); + return true; + } + case CStyleCastExprClass: + // If this is a cast to void, check the operand. Otherwise, the result of + // the cast is unused. + if (getType()->isVoidType()) + return cast<CastExpr>(this)->getSubExpr()->isUnusedResultAWarning(Loc, + R1, R2); + Loc = cast<CStyleCastExpr>(this)->getLParenLoc(); + R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange(); + return true; + case CXXFunctionalCastExprClass: + // If this is a cast to void, check the operand. Otherwise, the result of + // the cast is unused. + if (getType()->isVoidType()) + return cast<CastExpr>(this)->getSubExpr()->isUnusedResultAWarning(Loc, + R1, R2); + Loc = cast<CXXFunctionalCastExpr>(this)->getTypeBeginLoc(); + R1 = cast<CXXFunctionalCastExpr>(this)->getSubExpr()->getSourceRange(); + return true; + + case ImplicitCastExprClass: + // Check the operand, since implicit casts are inserted by Sema + return cast<ImplicitCastExpr>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + + case CXXDefaultArgExprClass: + return cast<CXXDefaultArgExpr>(this) + ->getExpr()->isUnusedResultAWarning(Loc, R1, R2); + + case CXXNewExprClass: + // FIXME: In theory, there might be new expressions that don't have side + // effects (e.g. a placement new with an uninitialized POD). + case CXXDeleteExprClass: + return false; + case CXXExprWithTemporariesClass: + return cast<CXXExprWithTemporaries>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + } +} + +/// DeclCanBeLvalue - Determine whether the given declaration can be +/// an lvalue. This is a helper routine for isLvalue. +static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) { + // C++ [temp.param]p6: + // A non-type non-reference template-parameter is not an lvalue. + if (const NonTypeTemplateParmDecl *NTTParm + = dyn_cast<NonTypeTemplateParmDecl>(Decl)) + return NTTParm->getType()->isReferenceType(); + + return isa<VarDecl>(Decl) || isa<FieldDecl>(Decl) || + // C++ 3.10p2: An lvalue refers to an object or function. + (Ctx.getLangOptions().CPlusPlus && + (isa<FunctionDecl>(Decl) || isa<OverloadedFunctionDecl>(Decl))); +} + +/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an +/// incomplete type other than void. Nonarray expressions that can be lvalues: +/// - name, where name must be a variable +/// - e[i] +/// - (e), where e must be an lvalue +/// - e.name, where e must be an lvalue +/// - e->name +/// - *e, the type of e cannot be a function type +/// - string-constant +/// - (__real__ e) and (__imag__ e) where e is an lvalue [GNU extension] +/// - reference type [C++ [expr]] +/// +Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const { + assert(!TR->isReferenceType() && "Expressions can't have reference type."); + + isLvalueResult Res = isLvalueInternal(Ctx); + if (Res != LV_Valid || Ctx.getLangOptions().CPlusPlus) + return Res; + + // first, check the type (C99 6.3.2.1). Expressions with function + // type in C are not lvalues, but they can be lvalues in C++. + if (TR->isFunctionType()) + return LV_NotObjectType; + + // Allow qualified void which is an incomplete type other than void (yuck). + if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers()) + return LV_IncompleteVoidType; + + return LV_Valid; +} + +// Check whether the expression can be sanely treated like an l-value +Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { + switch (getStmtClass()) { + case StringLiteralClass: // C99 6.5.1p4 + case ObjCEncodeExprClass: // @encode behaves like its string in every way. + return LV_Valid; + case ArraySubscriptExprClass: // C99 6.5.3p4 (e1[e2] == (*((e1)+(e2)))) + // For vectors, make sure base is an lvalue (i.e. not a function call). + if (cast<ArraySubscriptExpr>(this)->getBase()->getType()->isVectorType()) + return cast<ArraySubscriptExpr>(this)->getBase()->isLvalue(Ctx); + return LV_Valid; + case DeclRefExprClass: + case QualifiedDeclRefExprClass: { // C99 6.5.1p2 + const NamedDecl *RefdDecl = cast<DeclRefExpr>(this)->getDecl(); + if (DeclCanBeLvalue(RefdDecl, Ctx)) + return LV_Valid; + break; + } + case BlockDeclRefExprClass: { + const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this); + if (isa<VarDecl>(BDR->getDecl())) + return LV_Valid; + break; + } + case MemberExprClass: { + const MemberExpr *m = cast<MemberExpr>(this); + if (Ctx.getLangOptions().CPlusPlus) { // C++ [expr.ref]p4: + NamedDecl *Member = m->getMemberDecl(); + // C++ [expr.ref]p4: + // If E2 is declared to have type "reference to T", then E1.E2 + // is an lvalue. + if (ValueDecl *Value = dyn_cast<ValueDecl>(Member)) + if (Value->getType()->isReferenceType()) + return LV_Valid; + + // -- If E2 is a static data member [...] then E1.E2 is an lvalue. + if (isa<VarDecl>(Member) && Member->getDeclContext()->isRecord()) + return LV_Valid; + + // -- If E2 is a non-static data member [...]. If E1 is an + // lvalue, then E1.E2 is an lvalue. + if (isa<FieldDecl>(Member)) + return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx); + + // -- If it refers to a static member function [...], then + // E1.E2 is an lvalue. + // -- Otherwise, if E1.E2 refers to a non-static member + // function [...], then E1.E2 is not an lvalue. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) + return Method->isStatic()? LV_Valid : LV_MemberFunction; + + // -- If E2 is a member enumerator [...], the expression E1.E2 + // is not an lvalue. + if (isa<EnumConstantDecl>(Member)) + return LV_InvalidExpression; + + // Not an lvalue. + return LV_InvalidExpression; + } + + // C99 6.5.2.3p4 + return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx); + } + case UnaryOperatorClass: + if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref) + return LV_Valid; // C99 6.5.3p4 + + if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Real || + cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Imag || + cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Extension) + return cast<UnaryOperator>(this)->getSubExpr()->isLvalue(Ctx); // GNU. + + if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.pre.incr]p1 + (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreInc || + cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreDec)) + return LV_Valid; + break; + case ImplicitCastExprClass: + return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid + : LV_InvalidExpression; + case ParenExprClass: // C99 6.5.1p5 + return cast<ParenExpr>(this)->getSubExpr()->isLvalue(Ctx); + case BinaryOperatorClass: + case CompoundAssignOperatorClass: { + const BinaryOperator *BinOp = cast<BinaryOperator>(this); + + if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.comma]p1 + BinOp->getOpcode() == BinaryOperator::Comma) + return BinOp->getRHS()->isLvalue(Ctx); + + // C++ [expr.mptr.oper]p6 + if ((BinOp->getOpcode() == BinaryOperator::PtrMemD || + BinOp->getOpcode() == BinaryOperator::PtrMemI) && + !BinOp->getType()->isFunctionType()) + return BinOp->getLHS()->isLvalue(Ctx); + + if (!BinOp->isAssignmentOp()) + return LV_InvalidExpression; + + if (Ctx.getLangOptions().CPlusPlus) + // C++ [expr.ass]p1: + // The result of an assignment operation [...] is an lvalue. + return LV_Valid; + + + // C99 6.5.16: + // An assignment expression [...] is not an lvalue. + return LV_InvalidExpression; + } + case CallExprClass: + case CXXOperatorCallExprClass: + case CXXMemberCallExprClass: { + // C++0x [expr.call]p10 + // A function call is an lvalue if and only if the result type + // is an lvalue reference. + QualType ReturnType = cast<CallExpr>(this)->getCallReturnType(); + if (ReturnType->isLValueReferenceType()) + return LV_Valid; + + break; + } + case CompoundLiteralExprClass: // C99 6.5.2.5p5 + return LV_Valid; + case ChooseExprClass: + // __builtin_choose_expr is an lvalue if the selected operand is. + return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)->isLvalue(Ctx); + case ExtVectorElementExprClass: + if (cast<ExtVectorElementExpr>(this)->containsDuplicateElements()) + return LV_DuplicateVectorComponents; + return LV_Valid; + case ObjCIvarRefExprClass: // ObjC instance variables are lvalues. + return LV_Valid; + case ObjCPropertyRefExprClass: // FIXME: check if read-only property. + return LV_Valid; + case ObjCKVCRefExprClass: // FIXME: check if read-only property. + return LV_Valid; + case PredefinedExprClass: + return LV_Valid; + case CXXDefaultArgExprClass: + return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx); + case CXXConditionDeclExprClass: + return LV_Valid; + case CStyleCastExprClass: + case CXXFunctionalCastExprClass: + case CXXStaticCastExprClass: + case CXXDynamicCastExprClass: + case CXXReinterpretCastExprClass: + case CXXConstCastExprClass: + // The result of an explicit cast is an lvalue if the type we are + // casting to is an lvalue reference type. See C++ [expr.cast]p1, + // C++ [expr.static.cast]p2, C++ [expr.dynamic.cast]p2, + // C++ [expr.reinterpret.cast]p1, C++ [expr.const.cast]p1. + if (cast<ExplicitCastExpr>(this)->getTypeAsWritten()-> + isLValueReferenceType()) + return LV_Valid; + break; + case CXXTypeidExprClass: + // C++ 5.2.8p1: The result of a typeid expression is an lvalue of ... + return LV_Valid; + case ConditionalOperatorClass: { + // Complicated handling is only for C++. + if (!Ctx.getLangOptions().CPlusPlus) + return LV_InvalidExpression; + + // Sema should have taken care to ensure that a CXXTemporaryObjectExpr is + // everywhere there's an object converted to an rvalue. Also, any other + // casts should be wrapped by ImplicitCastExprs. There's just the special + // case involving throws to work out. + const ConditionalOperator *Cond = cast<ConditionalOperator>(this); + Expr *True = Cond->getTrueExpr(); + Expr *False = Cond->getFalseExpr(); + // C++0x 5.16p2 + // If either the second or the third operand has type (cv) void, [...] + // the result [...] is an rvalue. + if (True->getType()->isVoidType() || False->getType()->isVoidType()) + return LV_InvalidExpression; + + // Both sides must be lvalues for the result to be an lvalue. + if (True->isLvalue(Ctx) != LV_Valid || False->isLvalue(Ctx) != LV_Valid) + return LV_InvalidExpression; + + // That's it. + return LV_Valid; + } + + default: + break; + } + return LV_InvalidExpression; +} + +/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, +/// does not have an incomplete type, does not have a const-qualified type, and +/// if it is a structure or union, does not have any member (including, +/// recursively, any member or element of all contained aggregates or unions) +/// with a const-qualified type. +Expr::isModifiableLvalueResult +Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { + isLvalueResult lvalResult = isLvalue(Ctx); + + switch (lvalResult) { + case LV_Valid: + // C++ 3.10p11: Functions cannot be modified, but pointers to + // functions can be modifiable. + if (Ctx.getLangOptions().CPlusPlus && TR->isFunctionType()) + return MLV_NotObjectType; + break; + + case LV_NotObjectType: return MLV_NotObjectType; + case LV_IncompleteVoidType: return MLV_IncompleteVoidType; + case LV_DuplicateVectorComponents: return MLV_DuplicateVectorComponents; + case LV_InvalidExpression: + // If the top level is a C-style cast, and the subexpression is a valid + // lvalue, then this is probably a use of the old-school "cast as lvalue" + // GCC extension. We don't support it, but we want to produce good + // diagnostics when it happens so that the user knows why. + if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(IgnoreParens())) { + if (CE->getSubExpr()->isLvalue(Ctx) == LV_Valid) { + if (Loc) + *Loc = CE->getLParenLoc(); + return MLV_LValueCast; + } + } + return MLV_InvalidExpression; + case LV_MemberFunction: return MLV_MemberFunction; + } + + // The following is illegal: + // void takeclosure(void (^C)(void)); + // void func() { int x = 1; takeclosure(^{ x = 7; }); } + // + if (isa<BlockDeclRefExpr>(this)) { + const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this); + if (!BDR->isByRef() && isa<VarDecl>(BDR->getDecl())) + return MLV_NotBlockQualified; + } + + QualType CT = Ctx.getCanonicalType(getType()); + + if (CT.isConstQualified()) + return MLV_ConstQualified; + if (CT->isArrayType()) + return MLV_ArrayType; + if (CT->isIncompleteType()) + return MLV_IncompleteType; + + if (const RecordType *r = CT->getAsRecordType()) { + if (r->hasConstFields()) + return MLV_ConstQualified; + } + + // Assigning to an 'implicit' property? + else if (isa<ObjCKVCRefExpr>(this)) { + const ObjCKVCRefExpr* KVCExpr = cast<ObjCKVCRefExpr>(this); + if (KVCExpr->getSetterMethod() == 0) + return MLV_NoSetterProperty; + } + return MLV_Valid; +} + +/// hasGlobalStorage - Return true if this expression has static storage +/// duration. This means that the address of this expression is a link-time +/// constant. +bool Expr::hasGlobalStorage() const { + switch (getStmtClass()) { + default: + return false; + case BlockExprClass: + return true; + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()->hasGlobalStorage(); + case ImplicitCastExprClass: + return cast<ImplicitCastExpr>(this)->getSubExpr()->hasGlobalStorage(); + case CompoundLiteralExprClass: + return cast<CompoundLiteralExpr>(this)->isFileScope(); + case DeclRefExprClass: + case QualifiedDeclRefExprClass: { + const Decl *D = cast<DeclRefExpr>(this)->getDecl(); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) + return VD->hasGlobalStorage(); + if (isa<FunctionDecl>(D)) + return true; + return false; + } + case MemberExprClass: { + const MemberExpr *M = cast<MemberExpr>(this); + return !M->isArrow() && M->getBase()->hasGlobalStorage(); + } + case ArraySubscriptExprClass: + return cast<ArraySubscriptExpr>(this)->getBase()->hasGlobalStorage(); + case PredefinedExprClass: + return true; + case CXXDefaultArgExprClass: + return cast<CXXDefaultArgExpr>(this)->getExpr()->hasGlobalStorage(); + } +} + +/// isOBJCGCCandidate - Check if an expression is objc gc'able. +/// +bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { + switch (getStmtClass()) { + default: + return false; + case ObjCIvarRefExprClass: + return true; + case Expr::UnaryOperatorClass: + return cast<UnaryOperator>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); + case ImplicitCastExprClass: + return cast<ImplicitCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); + case CStyleCastExprClass: + return cast<CStyleCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); + case DeclRefExprClass: + case QualifiedDeclRefExprClass: { + const Decl *D = cast<DeclRefExpr>(this)->getDecl(); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->hasGlobalStorage()) + return true; + QualType T = VD->getType(); + // dereferencing to an object pointer is always a gc'able candidate + if (T->isPointerType() && + Ctx.isObjCObjectPointerType(T->getAsPointerType()->getPointeeType())) + return true; + + } + return false; + } + case MemberExprClass: { + const MemberExpr *M = cast<MemberExpr>(this); + return M->getBase()->isOBJCGCCandidate(Ctx); + } + case ArraySubscriptExprClass: + return cast<ArraySubscriptExpr>(this)->getBase()->isOBJCGCCandidate(Ctx); + } +} +Expr* Expr::IgnoreParens() { + Expr* E = this; + while (ParenExpr* P = dyn_cast<ParenExpr>(E)) + E = P->getSubExpr(); + + return E; +} + +/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr +/// or CastExprs or ImplicitCastExprs, returning their operand. +Expr *Expr::IgnoreParenCasts() { + Expr *E = this; + while (true) { + if (ParenExpr *P = dyn_cast<ParenExpr>(E)) + E = P->getSubExpr(); + else if (CastExpr *P = dyn_cast<CastExpr>(E)) + E = P->getSubExpr(); + else + return E; + } +} + +/// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the +/// value (including ptr->int casts of the same size). Strip off any +/// ParenExpr or CastExprs, returning their operand. +Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { + Expr *E = this; + while (true) { + if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { + E = P->getSubExpr(); + continue; + } + + if (CastExpr *P = dyn_cast<CastExpr>(E)) { + // We ignore integer <-> casts that are of the same width, ptr<->ptr and + // ptr<->int casts of the same width. We also ignore all identify casts. + Expr *SE = P->getSubExpr(); + + if (Ctx.hasSameUnqualifiedType(E->getType(), SE->getType())) { + E = SE; + continue; + } + + if ((E->getType()->isPointerType() || E->getType()->isIntegralType()) && + (SE->getType()->isPointerType() || SE->getType()->isIntegralType()) && + Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SE->getType())) { + E = SE; + continue; + } + } + + return E; + } +} + + +/// hasAnyTypeDependentArguments - Determines if any of the expressions +/// in Exprs is type-dependent. +bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) { + for (unsigned I = 0; I < NumExprs; ++I) + if (Exprs[I]->isTypeDependent()) + return true; + + return false; +} + +/// hasAnyValueDependentArguments - Determines if any of the expressions +/// in Exprs is value-dependent. +bool Expr::hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs) { + for (unsigned I = 0; I < NumExprs; ++I) + if (Exprs[I]->isValueDependent()) + return true; + + return false; +} + +bool Expr::isConstantInitializer(ASTContext &Ctx) const { + // This function is attempting whether an expression is an initializer + // which can be evaluated at compile-time. isEvaluatable handles most + // of the cases, but it can't deal with some initializer-specific + // expressions, and it can't deal with aggregates; we deal with those here, + // and fall back to isEvaluatable for the other cases. + + // FIXME: This function assumes the variable being assigned to + // isn't a reference type! + + switch (getStmtClass()) { + default: break; + case StringLiteralClass: + case ObjCEncodeExprClass: + return true; + case CompoundLiteralExprClass: { + // This handles gcc's extension that allows global initializers like + // "struct x {int x;} x = (struct x) {};". + // FIXME: This accepts other cases it shouldn't! + const Expr *Exp = cast<CompoundLiteralExpr>(this)->getInitializer(); + return Exp->isConstantInitializer(Ctx); + } + case InitListExprClass: { + // FIXME: This doesn't deal with fields with reference types correctly. + // FIXME: This incorrectly allows pointers cast to integers to be assigned + // to bitfields. + const InitListExpr *Exp = cast<InitListExpr>(this); + unsigned numInits = Exp->getNumInits(); + for (unsigned i = 0; i < numInits; i++) { + if (!Exp->getInit(i)->isConstantInitializer(Ctx)) + return false; + } + return true; + } + case ImplicitValueInitExprClass: + return true; + case ParenExprClass: { + return cast<ParenExpr>(this)->getSubExpr()->isConstantInitializer(Ctx); + } + case UnaryOperatorClass: { + const UnaryOperator* Exp = cast<UnaryOperator>(this); + if (Exp->getOpcode() == UnaryOperator::Extension) + return Exp->getSubExpr()->isConstantInitializer(Ctx); + break; + } + case ImplicitCastExprClass: + case CStyleCastExprClass: + // Handle casts with a destination that's a struct or union; this + // deals with both the gcc no-op struct cast extension and the + // cast-to-union extension. + if (getType()->isRecordType()) + return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx); + break; + } + + return isEvaluatable(Ctx); +} + +/// isIntegerConstantExpr - this recursive routine will test if an expression is +/// an integer constant expression. + +/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero, +/// comma, etc +/// +/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof +/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer +/// cast+dereference. + +// CheckICE - This function does the fundamental ICE checking: the returned +// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation. +// Note that to reduce code duplication, this helper does no evaluation +// itself; the caller checks whether the expression is evaluatable, and +// in the rare cases where CheckICE actually cares about the evaluated +// value, it calls into Evalute. +// +// Meanings of Val: +// 0: This expression is an ICE if it can be evaluated by Evaluate. +// 1: This expression is not an ICE, but if it isn't evaluated, it's +// a legal subexpression for an ICE. This return value is used to handle +// the comma operator in C99 mode. +// 2: This expression is not an ICE, and is not a legal subexpression for one. + +struct ICEDiag { + unsigned Val; + SourceLocation Loc; + + public: + ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {} + ICEDiag() : Val(0) {} +}; + +ICEDiag NoDiag() { return ICEDiag(); } + +static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) { + Expr::EvalResult EVResult; + if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || + !EVResult.Val.isInt()) { + return ICEDiag(2, E->getLocStart()); + } + return NoDiag(); +} + +static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { + assert(!E->isValueDependent() && "Should not see value dependent exprs!"); + if (!E->getType()->isIntegralType()) { + return ICEDiag(2, E->getLocStart()); + } + + switch (E->getStmtClass()) { + default: + return ICEDiag(2, E->getLocStart()); + case Expr::ParenExprClass: + return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx); + case Expr::IntegerLiteralClass: + case Expr::CharacterLiteralClass: + case Expr::CXXBoolLiteralExprClass: + case Expr::CXXZeroInitValueExprClass: + case Expr::TypesCompatibleExprClass: + case Expr::UnaryTypeTraitExprClass: + return NoDiag(); + case Expr::CallExprClass: + case Expr::CXXOperatorCallExprClass: { + const CallExpr *CE = cast<CallExpr>(E); + if (CE->isBuiltinCall(Ctx)) + return CheckEvalInICE(E, Ctx); + return ICEDiag(2, E->getLocStart()); + } + case Expr::DeclRefExprClass: + case Expr::QualifiedDeclRefExprClass: + if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) + return NoDiag(); + if (Ctx.getLangOptions().CPlusPlus && + E->getType().getCVRQualifiers() == QualType::Const) { + // C++ 7.1.5.1p2 + // A variable of non-volatile const-qualified integral or enumeration + // type initialized by an ICE can be used in ICEs. + if (const VarDecl *Dcl = + dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) { + if (Dcl->isInitKnownICE()) { + // We have already checked whether this subexpression is an + // integral constant expression. + if (Dcl->isInitICE()) + return NoDiag(); + else + return ICEDiag(2, E->getLocStart()); + } + + if (const Expr *Init = Dcl->getInit()) { + ICEDiag Result = CheckICE(Init, Ctx); + // Cache the result of the ICE test. + Dcl->setInitKnownICE(Ctx, Result.Val == 0); + return Result; + } + } + } + return ICEDiag(2, E->getLocStart()); + case Expr::UnaryOperatorClass: { + const UnaryOperator *Exp = cast<UnaryOperator>(E); + switch (Exp->getOpcode()) { + default: + return ICEDiag(2, E->getLocStart()); + case UnaryOperator::Extension: + case UnaryOperator::LNot: + case UnaryOperator::Plus: + case UnaryOperator::Minus: + case UnaryOperator::Not: + case UnaryOperator::Real: + case UnaryOperator::Imag: + return CheckICE(Exp->getSubExpr(), Ctx); + case UnaryOperator::OffsetOf: + // Note that per C99, offsetof must be an ICE. And AFAIK, using + // Evaluate matches the proposed gcc behavior for cases like + // "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect + // compliance: we should warn earlier for offsetof expressions with + // array subscripts that aren't ICEs, and if the array subscripts + // are ICEs, the value of the offsetof must be an integer constant. + return CheckEvalInICE(E, Ctx); + } + } + case Expr::SizeOfAlignOfExprClass: { + const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E); + if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType()) + return ICEDiag(2, E->getLocStart()); + return NoDiag(); + } + case Expr::BinaryOperatorClass: { + const BinaryOperator *Exp = cast<BinaryOperator>(E); + switch (Exp->getOpcode()) { + default: + return ICEDiag(2, E->getLocStart()); + case BinaryOperator::Mul: + case BinaryOperator::Div: + case BinaryOperator::Rem: + case BinaryOperator::Add: + case BinaryOperator::Sub: + case BinaryOperator::Shl: + case BinaryOperator::Shr: + case BinaryOperator::LT: + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: + case BinaryOperator::NE: + case BinaryOperator::And: + case BinaryOperator::Xor: + case BinaryOperator::Or: + case BinaryOperator::Comma: { + ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); + ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); + if (Exp->getOpcode() == BinaryOperator::Div || + Exp->getOpcode() == BinaryOperator::Rem) { + // Evaluate gives an error for undefined Div/Rem, so make sure + // we don't evaluate one. + if (LHSResult.Val != 2 && RHSResult.Val != 2) { + llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx); + if (REval == 0) + return ICEDiag(1, E->getLocStart()); + if (REval.isSigned() && REval.isAllOnesValue()) { + llvm::APSInt LEval = Exp->getLHS()->EvaluateAsInt(Ctx); + if (LEval.isMinSignedValue()) + return ICEDiag(1, E->getLocStart()); + } + } + } + if (Exp->getOpcode() == BinaryOperator::Comma) { + if (Ctx.getLangOptions().C99) { + // C99 6.6p3 introduces a strange edge case: comma can be in an ICE + // if it isn't evaluated. + if (LHSResult.Val == 0 && RHSResult.Val == 0) + return ICEDiag(1, E->getLocStart()); + } else { + // In both C89 and C++, commas in ICEs are illegal. + return ICEDiag(2, E->getLocStart()); + } + } + if (LHSResult.Val >= RHSResult.Val) + return LHSResult; + return RHSResult; + } + case BinaryOperator::LAnd: + case BinaryOperator::LOr: { + ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); + ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); + if (LHSResult.Val == 0 && RHSResult.Val == 1) { + // Rare case where the RHS has a comma "side-effect"; we need + // to actually check the condition to see whether the side + // with the comma is evaluated. + if ((Exp->getOpcode() == BinaryOperator::LAnd) != + (Exp->getLHS()->EvaluateAsInt(Ctx) == 0)) + return RHSResult; + return NoDiag(); + } + + if (LHSResult.Val >= RHSResult.Val) + return LHSResult; + return RHSResult; + } + } + } + case Expr::ImplicitCastExprClass: + case Expr::CStyleCastExprClass: + case Expr::CXXFunctionalCastExprClass: { + const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr(); + if (SubExpr->getType()->isIntegralType()) + return CheckICE(SubExpr, Ctx); + if (isa<FloatingLiteral>(SubExpr->IgnoreParens())) + return NoDiag(); + return ICEDiag(2, E->getLocStart()); + } + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast<ConditionalOperator>(E); + // If the condition (ignoring parens) is a __builtin_constant_p call, + // then only the true side is actually considered in an integer constant + // expression, and it is fully evaluated. This is an important GNU + // extension. See GCC PR38377 for discussion. + if (const CallExpr *CallCE = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts())) + if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) { + Expr::EvalResult EVResult; + if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || + !EVResult.Val.isInt()) { + return ICEDiag(2, E->getLocStart()); + } + return NoDiag(); + } + ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx); + ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx); + ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); + if (CondResult.Val == 2) + return CondResult; + if (TrueResult.Val == 2) + return TrueResult; + if (FalseResult.Val == 2) + return FalseResult; + if (CondResult.Val == 1) + return CondResult; + if (TrueResult.Val == 0 && FalseResult.Val == 0) + return NoDiag(); + // Rare case where the diagnostics depend on which side is evaluated + // Note that if we get here, CondResult is 0, and at least one of + // TrueResult and FalseResult is non-zero. + if (Exp->getCond()->EvaluateAsInt(Ctx) == 0) { + return FalseResult; + } + return TrueResult; + } + case Expr::CXXDefaultArgExprClass: + return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx); + case Expr::ChooseExprClass: { + return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx); + } + } +} + +bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, + SourceLocation *Loc, bool isEvaluated) const { + ICEDiag d = CheckICE(this, Ctx); + if (d.Val != 0) { + if (Loc) *Loc = d.Loc; + return false; + } + EvalResult EvalResult; + if (!Evaluate(EvalResult, Ctx)) + assert(0 && "ICE cannot be evaluated!"); + assert(!EvalResult.HasSideEffects && "ICE with side effects!"); + assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); + Result = EvalResult.Val.getInt(); + return true; +} + +/// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an +/// integer constant expression with the value zero, or if this is one that is +/// cast to void*. +bool Expr::isNullPointerConstant(ASTContext &Ctx) const +{ + // Strip off a cast to void*, if it exists. Except in C++. + if (const ExplicitCastExpr *CE = dyn_cast<ExplicitCastExpr>(this)) { + if (!Ctx.getLangOptions().CPlusPlus) { + // Check that it is a cast to void*. + if (const PointerType *PT = CE->getType()->getAsPointerType()) { + QualType Pointee = PT->getPointeeType(); + if (Pointee.getCVRQualifiers() == 0 && + Pointee->isVoidType() && // to void* + CE->getSubExpr()->getType()->isIntegerType()) // from int. + return CE->getSubExpr()->isNullPointerConstant(Ctx); + } + } + } else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(this)) { + // Ignore the ImplicitCastExpr type entirely. + return ICE->getSubExpr()->isNullPointerConstant(Ctx); + } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(this)) { + // Accept ((void*)0) as a null pointer constant, as many other + // implementations do. + return PE->getSubExpr()->isNullPointerConstant(Ctx); + } else if (const CXXDefaultArgExpr *DefaultArg + = dyn_cast<CXXDefaultArgExpr>(this)) { + // See through default argument expressions + return DefaultArg->getExpr()->isNullPointerConstant(Ctx); + } else if (isa<GNUNullExpr>(this)) { + // The GNU __null extension is always a null pointer constant. + return true; + } + + // C++0x nullptr_t is always a null pointer constant. + if (getType()->isNullPtrType()) + return true; + + // This expression must be an integer type. + if (!getType()->isIntegerType()) + return false; + + // If we have an integer constant expression, we need to *evaluate* it and + // test for the value 0. + llvm::APSInt Result; + return isIntegerConstantExpr(Result, Ctx) && Result == 0; +} + +FieldDecl *Expr::getBitField() { + Expr *E = this->IgnoreParenCasts(); + + if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E)) + if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl())) + if (Field->isBitField()) + return Field; + + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E)) + if (BinOp->isAssignmentOp() && BinOp->getLHS()) + return BinOp->getLHS()->getBitField(); + + return 0; +} + +/// isArrow - Return true if the base expression is a pointer to vector, +/// return false if the base expression is a vector. +bool ExtVectorElementExpr::isArrow() const { + return getBase()->getType()->isPointerType(); +} + +unsigned ExtVectorElementExpr::getNumElements() const { + if (const VectorType *VT = getType()->getAsVectorType()) + return VT->getNumElements(); + return 1; +} + +/// containsDuplicateElements - Return true if any element access is repeated. +bool ExtVectorElementExpr::containsDuplicateElements() const { + const char *compStr = Accessor->getName(); + unsigned length = Accessor->getLength(); + + // Halving swizzles do not contain duplicate elements. + if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || + !strcmp(compStr, "even") || !strcmp(compStr, "odd")) + return false; + + // Advance past s-char prefix on hex swizzles. + if (*compStr == 's') { + compStr++; + length--; + } + + for (unsigned i = 0; i != length-1; i++) { + const char *s = compStr+i; + for (const char c = *s++; *s; s++) + if (c == *s) + return true; + } + return false; +} + +/// getEncodedElementAccess - We encode the fields as a llvm ConstantArray. +void ExtVectorElementExpr::getEncodedElementAccess( + llvm::SmallVectorImpl<unsigned> &Elts) const { + const char *compStr = Accessor->getName(); + if (*compStr == 's') + compStr++; + + bool isHi = !strcmp(compStr, "hi"); + bool isLo = !strcmp(compStr, "lo"); + bool isEven = !strcmp(compStr, "even"); + bool isOdd = !strcmp(compStr, "odd"); + + for (unsigned i = 0, e = getNumElements(); i != e; ++i) { + uint64_t Index; + + if (isHi) + Index = e + i; + else if (isLo) + Index = i; + else if (isEven) + Index = 2 * i; + else if (isOdd) + Index = 2 * i + 1; + else + Index = ExtVectorType::getAccessorIdx(compStr[i]); + + Elts.push_back(Index); + } +} + +// constructor for instance messages. +ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + MethodProto(mproto) { + NumArgs = nargs; + SubExprs = new Stmt*[NumArgs+1]; + SubExprs[RECEIVER] = receiver; + if (NumArgs) { + for (unsigned i = 0; i != NumArgs; ++i) + SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]); + } + LBracloc = LBrac; + RBracloc = RBrac; +} + +// constructor for class messages. +// FIXME: clsName should be typed to ObjCInterfaceType +ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + MethodProto(mproto) { + NumArgs = nargs; + SubExprs = new Stmt*[NumArgs+1]; + SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown); + if (NumArgs) { + for (unsigned i = 0; i != NumArgs; ++i) + SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]); + } + LBracloc = LBrac; + RBracloc = RBrac; +} + +// constructor for class messages. +ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) +: Expr(ObjCMessageExprClass, retType), SelName(selInfo), +MethodProto(mproto) { + NumArgs = nargs; + SubExprs = new Stmt*[NumArgs+1]; + SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown); + if (NumArgs) { + for (unsigned i = 0; i != NumArgs; ++i) + SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]); + } + LBracloc = LBrac; + RBracloc = RBrac; +} + +ObjCMessageExpr::ClassInfo ObjCMessageExpr::getClassInfo() const { + uintptr_t x = (uintptr_t) SubExprs[RECEIVER]; + switch (x & Flags) { + default: + assert(false && "Invalid ObjCMessageExpr."); + case IsInstMeth: + return ClassInfo(0, 0); + case IsClsMethDeclUnknown: + return ClassInfo(0, (IdentifierInfo*) (x & ~Flags)); + case IsClsMethDeclKnown: { + ObjCInterfaceDecl* D = (ObjCInterfaceDecl*) (x & ~Flags); + return ClassInfo(D, D->getIdentifier()); + } + } +} + +void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) { + if (CI.first == 0 && CI.second == 0) + SubExprs[RECEIVER] = (Expr*)((uintptr_t)0 | IsInstMeth); + else if (CI.first == 0) + SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.second | IsClsMethDeclUnknown); + else + SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.first | IsClsMethDeclKnown); +} + + +bool ChooseExpr::isConditionTrue(ASTContext &C) const { + return getCond()->EvaluateAsInt(C) != 0; +} + +void ShuffleVectorExpr::setExprs(Expr ** Exprs, unsigned NumExprs) { + if (NumExprs) + delete [] SubExprs; + + SubExprs = new Stmt* [NumExprs]; + this->NumExprs = NumExprs; + memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs); +} + +void SizeOfAlignOfExpr::Destroy(ASTContext& C) { + // Override default behavior of traversing children. If this has a type + // operand and the type is a variable-length array, the child iteration + // will iterate over the size expression. However, this expression belongs + // to the type, not to this, so we don't want to delete it. + // We still want to delete this expression. + if (isArgumentType()) { + this->~SizeOfAlignOfExpr(); + C.Deallocate(this); + } + else + Expr::Destroy(C); +} + +//===----------------------------------------------------------------------===// +// DesignatedInitExpr +//===----------------------------------------------------------------------===// + +IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + if (Field.NameOrField & 0x01) + return reinterpret_cast<IdentifierInfo *>(Field.NameOrField&~0x01); + else + return getField()->getIdentifier(); +} + +DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, + const Designator *Designators, + SourceLocation EqualOrColonLoc, + bool GNUSyntax, + Expr **IndexExprs, + unsigned NumIndexExprs, + Expr *Init) + : Expr(DesignatedInitExprClass, Ty, + Init->isTypeDependent(), Init->isValueDependent()), + EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), + NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { + this->Designators = new Designator[NumDesignators]; + + // Record the initializer itself. + child_iterator Child = child_begin(); + *Child++ = Init; + + // Copy the designators and their subexpressions, computing + // value-dependence along the way. + unsigned IndexIdx = 0; + for (unsigned I = 0; I != NumDesignators; ++I) { + this->Designators[I] = Designators[I]; + + if (this->Designators[I].isArrayDesignator()) { + // Compute type- and value-dependence. + Expr *Index = IndexExprs[IndexIdx]; + ValueDependent = ValueDependent || + Index->isTypeDependent() || Index->isValueDependent(); + + // Copy the index expressions into permanent storage. + *Child++ = IndexExprs[IndexIdx++]; + } else if (this->Designators[I].isArrayRangeDesignator()) { + // Compute type- and value-dependence. + Expr *Start = IndexExprs[IndexIdx]; + Expr *End = IndexExprs[IndexIdx + 1]; + ValueDependent = ValueDependent || + Start->isTypeDependent() || Start->isValueDependent() || + End->isTypeDependent() || End->isValueDependent(); + + // Copy the start/end expressions into permanent storage. + *Child++ = IndexExprs[IndexIdx++]; + *Child++ = IndexExprs[IndexIdx++]; + } + } + + assert(IndexIdx == NumIndexExprs && "Wrong number of index expressions"); +} + +DesignatedInitExpr * +DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, + unsigned NumDesignators, + Expr **IndexExprs, unsigned NumIndexExprs, + SourceLocation ColonOrEqualLoc, + bool UsesColonSyntax, Expr *Init) { + void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + + sizeof(Stmt *) * (NumIndexExprs + 1), 8); + return new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators, + ColonOrEqualLoc, UsesColonSyntax, + IndexExprs, NumIndexExprs, Init); +} + +DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, + unsigned NumIndexExprs) { + void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + + sizeof(Stmt *) * (NumIndexExprs + 1), 8); + return new (Mem) DesignatedInitExpr(NumIndexExprs + 1); +} + +void DesignatedInitExpr::setDesignators(const Designator *Desigs, + unsigned NumDesigs) { + if (Designators) + delete [] Designators; + + Designators = new Designator[NumDesigs]; + NumDesignators = NumDesigs; + for (unsigned I = 0; I != NumDesigs; ++I) + Designators[I] = Desigs[I]; +} + +SourceRange DesignatedInitExpr::getSourceRange() const { + SourceLocation StartLoc; + Designator &First = + *const_cast<DesignatedInitExpr*>(this)->designators_begin(); + if (First.isFieldDesignator()) { + if (GNUSyntax) + StartLoc = SourceLocation::getFromRawEncoding(First.Field.FieldLoc); + else + StartLoc = SourceLocation::getFromRawEncoding(First.Field.DotLoc); + } else + StartLoc = + SourceLocation::getFromRawEncoding(First.ArrayOrRange.LBracketLoc); + return SourceRange(StartLoc, getInit()->getSourceRange().getEnd()); +} + +Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) { + assert(D.Kind == Designator::ArrayDesignator && "Requires array designator"); + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); + return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1)); +} + +Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) { + assert(D.Kind == Designator::ArrayRangeDesignator && + "Requires array range designator"); + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); + return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1)); +} + +Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) { + assert(D.Kind == Designator::ArrayRangeDesignator && + "Requires array range designator"); + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); + return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2)); +} + +/// \brief Replaces the designator at index @p Idx with the series +/// of designators in [First, Last). +void DesignatedInitExpr::ExpandDesignator(unsigned Idx, + const Designator *First, + const Designator *Last) { + unsigned NumNewDesignators = Last - First; + if (NumNewDesignators == 0) { + std::copy_backward(Designators + Idx + 1, + Designators + NumDesignators, + Designators + Idx); + --NumNewDesignators; + return; + } else if (NumNewDesignators == 1) { + Designators[Idx] = *First; + return; + } + + Designator *NewDesignators + = new Designator[NumDesignators - 1 + NumNewDesignators]; + std::copy(Designators, Designators + Idx, NewDesignators); + std::copy(First, Last, NewDesignators + Idx); + std::copy(Designators + Idx + 1, Designators + NumDesignators, + NewDesignators + Idx + NumNewDesignators); + delete [] Designators; + Designators = NewDesignators; + NumDesignators = NumDesignators - 1 + NumNewDesignators; +} + +void DesignatedInitExpr::Destroy(ASTContext &C) { + delete [] Designators; + Expr::Destroy(C); +} + +ImplicitValueInitExpr *ImplicitValueInitExpr::Clone(ASTContext &C) const { + return new (C) ImplicitValueInitExpr(getType()); +} + +//===----------------------------------------------------------------------===// +// ExprIterator. +//===----------------------------------------------------------------------===// + +Expr* ExprIterator::operator[](size_t idx) { return cast<Expr>(I[idx]); } +Expr* ExprIterator::operator*() const { return cast<Expr>(*I); } +Expr* ExprIterator::operator->() const { return cast<Expr>(*I); } +const Expr* ConstExprIterator::operator[](size_t idx) const { + return cast<Expr>(I[idx]); +} +const Expr* ConstExprIterator::operator*() const { return cast<Expr>(*I); } +const Expr* ConstExprIterator::operator->() const { return cast<Expr>(*I); } + +//===----------------------------------------------------------------------===// +// Child Iterators for iterating over subexpressions/substatements +//===----------------------------------------------------------------------===// + +// DeclRefExpr +Stmt::child_iterator DeclRefExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator DeclRefExpr::child_end() { return child_iterator(); } + +// ObjCIvarRefExpr +Stmt::child_iterator ObjCIvarRefExpr::child_begin() { return &Base; } +Stmt::child_iterator ObjCIvarRefExpr::child_end() { return &Base+1; } + +// ObjCPropertyRefExpr +Stmt::child_iterator ObjCPropertyRefExpr::child_begin() { return &Base; } +Stmt::child_iterator ObjCPropertyRefExpr::child_end() { return &Base+1; } + +// ObjCKVCRefExpr +Stmt::child_iterator ObjCKVCRefExpr::child_begin() { return &Base; } +Stmt::child_iterator ObjCKVCRefExpr::child_end() { return &Base+1; } + +// ObjCSuperExpr +Stmt::child_iterator ObjCSuperExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator ObjCSuperExpr::child_end() { return child_iterator(); } + +// PredefinedExpr +Stmt::child_iterator PredefinedExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator PredefinedExpr::child_end() { return child_iterator(); } + +// IntegerLiteral +Stmt::child_iterator IntegerLiteral::child_begin() { return child_iterator(); } +Stmt::child_iterator IntegerLiteral::child_end() { return child_iterator(); } + +// CharacterLiteral +Stmt::child_iterator CharacterLiteral::child_begin() { return child_iterator();} +Stmt::child_iterator CharacterLiteral::child_end() { return child_iterator(); } + +// FloatingLiteral +Stmt::child_iterator FloatingLiteral::child_begin() { return child_iterator(); } +Stmt::child_iterator FloatingLiteral::child_end() { return child_iterator(); } + +// ImaginaryLiteral +Stmt::child_iterator ImaginaryLiteral::child_begin() { return &Val; } +Stmt::child_iterator ImaginaryLiteral::child_end() { return &Val+1; } + +// StringLiteral +Stmt::child_iterator StringLiteral::child_begin() { return child_iterator(); } +Stmt::child_iterator StringLiteral::child_end() { return child_iterator(); } + +// ParenExpr +Stmt::child_iterator ParenExpr::child_begin() { return &Val; } +Stmt::child_iterator ParenExpr::child_end() { return &Val+1; } + +// UnaryOperator +Stmt::child_iterator UnaryOperator::child_begin() { return &Val; } +Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; } + +// SizeOfAlignOfExpr +Stmt::child_iterator SizeOfAlignOfExpr::child_begin() { + // If this is of a type and the type is a VLA type (and not a typedef), the + // size expression of the VLA needs to be treated as an executable expression. + // Why isn't this weirdness documented better in StmtIterator? + if (isArgumentType()) { + if (VariableArrayType* T = dyn_cast<VariableArrayType>( + getArgumentType().getTypePtr())) + return child_iterator(T); + return child_iterator(); + } + return child_iterator(&Argument.Ex); +} +Stmt::child_iterator SizeOfAlignOfExpr::child_end() { + if (isArgumentType()) + return child_iterator(); + return child_iterator(&Argument.Ex + 1); +} + +// ArraySubscriptExpr +Stmt::child_iterator ArraySubscriptExpr::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator ArraySubscriptExpr::child_end() { + return &SubExprs[0]+END_EXPR; +} + +// CallExpr +Stmt::child_iterator CallExpr::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator CallExpr::child_end() { + return &SubExprs[0]+NumArgs+ARGS_START; +} + +// MemberExpr +Stmt::child_iterator MemberExpr::child_begin() { return &Base; } +Stmt::child_iterator MemberExpr::child_end() { return &Base+1; } + +// ExtVectorElementExpr +Stmt::child_iterator ExtVectorElementExpr::child_begin() { return &Base; } +Stmt::child_iterator ExtVectorElementExpr::child_end() { return &Base+1; } + +// CompoundLiteralExpr +Stmt::child_iterator CompoundLiteralExpr::child_begin() { return &Init; } +Stmt::child_iterator CompoundLiteralExpr::child_end() { return &Init+1; } + +// CastExpr +Stmt::child_iterator CastExpr::child_begin() { return &Op; } +Stmt::child_iterator CastExpr::child_end() { return &Op+1; } + +// BinaryOperator +Stmt::child_iterator BinaryOperator::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator BinaryOperator::child_end() { + return &SubExprs[0]+END_EXPR; +} + +// ConditionalOperator +Stmt::child_iterator ConditionalOperator::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator ConditionalOperator::child_end() { + return &SubExprs[0]+END_EXPR; +} + +// AddrLabelExpr +Stmt::child_iterator AddrLabelExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator AddrLabelExpr::child_end() { return child_iterator(); } + +// StmtExpr +Stmt::child_iterator StmtExpr::child_begin() { return &SubStmt; } +Stmt::child_iterator StmtExpr::child_end() { return &SubStmt+1; } + +// TypesCompatibleExpr +Stmt::child_iterator TypesCompatibleExpr::child_begin() { + return child_iterator(); +} + +Stmt::child_iterator TypesCompatibleExpr::child_end() { + return child_iterator(); +} + +// ChooseExpr +Stmt::child_iterator ChooseExpr::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator ChooseExpr::child_end() { return &SubExprs[0]+END_EXPR; } + +// GNUNullExpr +Stmt::child_iterator GNUNullExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator GNUNullExpr::child_end() { return child_iterator(); } + +// ShuffleVectorExpr +Stmt::child_iterator ShuffleVectorExpr::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator ShuffleVectorExpr::child_end() { + return &SubExprs[0]+NumExprs; +} + +// VAArgExpr +Stmt::child_iterator VAArgExpr::child_begin() { return &Val; } +Stmt::child_iterator VAArgExpr::child_end() { return &Val+1; } + +// InitListExpr +Stmt::child_iterator InitListExpr::child_begin() { + return InitExprs.size() ? &InitExprs[0] : 0; +} +Stmt::child_iterator InitListExpr::child_end() { + return InitExprs.size() ? &InitExprs[0] + InitExprs.size() : 0; +} + +// DesignatedInitExpr +Stmt::child_iterator DesignatedInitExpr::child_begin() { + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + return reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); +} +Stmt::child_iterator DesignatedInitExpr::child_end() { + return child_iterator(&*child_begin() + NumSubExprs); +} + +// ImplicitValueInitExpr +Stmt::child_iterator ImplicitValueInitExpr::child_begin() { + return child_iterator(); +} + +Stmt::child_iterator ImplicitValueInitExpr::child_end() { + return child_iterator(); +} + +// ObjCStringLiteral +Stmt::child_iterator ObjCStringLiteral::child_begin() { + return &String; +} +Stmt::child_iterator ObjCStringLiteral::child_end() { + return &String+1; +} + +// ObjCEncodeExpr +Stmt::child_iterator ObjCEncodeExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator ObjCEncodeExpr::child_end() { return child_iterator(); } + +// ObjCSelectorExpr +Stmt::child_iterator ObjCSelectorExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator ObjCSelectorExpr::child_end() { + return child_iterator(); +} + +// ObjCProtocolExpr +Stmt::child_iterator ObjCProtocolExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator ObjCProtocolExpr::child_end() { + return child_iterator(); +} + +// ObjCMessageExpr +Stmt::child_iterator ObjCMessageExpr::child_begin() { + return getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START; +} +Stmt::child_iterator ObjCMessageExpr::child_end() { + return &SubExprs[0]+ARGS_START+getNumArgs(); +} + +// Blocks +Stmt::child_iterator BlockExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator BlockExpr::child_end() { return child_iterator(); } + +Stmt::child_iterator BlockDeclRefExpr::child_begin() { return child_iterator();} +Stmt::child_iterator BlockDeclRefExpr::child_end() { return child_iterator(); } |