2007-07-11 21:01:13 +04:00
|
|
|
//===--- Expr.cpp - Expression AST Node Implementation --------------------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
2007-12-29 22:59:25 +03:00
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
2007-07-11 21:01:13 +04:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the Expr class and subclasses.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "clang/AST/Expr.h"
|
2007-07-16 03:32:58 +04:00
|
|
|
#include "clang/AST/ASTContext.h"
|
2007-07-11 21:01:13 +04:00
|
|
|
#include "clang/AST/StmtVisitor.h"
|
2007-10-07 12:58:51 +04:00
|
|
|
#include "clang/Basic/IdentifierTable.h"
|
2007-11-27 21:22:04 +03:00
|
|
|
#include "clang/Basic/TargetInfo.h"
|
2007-07-11 21:01:13 +04:00
|
|
|
using namespace clang;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Primary Expressions.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
StringLiteral::StringLiteral(const char *strData, unsigned byteLength,
|
|
|
|
bool Wide, QualType t, SourceLocation firstLoc,
|
|
|
|
SourceLocation lastLoc) :
|
|
|
|
Expr(StringLiteralClass, t) {
|
|
|
|
// OPTIMIZE: could allocate this appended to the StringLiteral.
|
|
|
|
char *AStrData = new char[byteLength];
|
|
|
|
memcpy(AStrData, strData, byteLength);
|
|
|
|
StrData = AStrData;
|
|
|
|
ByteLength = byteLength;
|
|
|
|
IsWide = Wide;
|
|
|
|
firstTokLoc = firstLoc;
|
|
|
|
lastTokLoc = lastLoc;
|
|
|
|
}
|
|
|
|
|
|
|
|
StringLiteral::~StringLiteral() {
|
|
|
|
delete[] StrData;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UnaryOperator::isPostfix(Opcode Op) {
|
|
|
|
switch (Op) {
|
|
|
|
case PostInc:
|
|
|
|
case PostDec:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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 SizeOf: return "sizeof";
|
|
|
|
case AlignOf: return "alignof";
|
|
|
|
case Extension: return "__extension__";
|
2007-08-30 21:45:32 +04:00
|
|
|
case OffsetOf: return "__builtin_offsetof";
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Postfix Operators.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2008-01-17 20:46:27 +03:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
CallExpr::CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t,
|
|
|
|
SourceLocation rparenloc)
|
2007-08-24 22:13:47 +04:00
|
|
|
: Expr(CallExprClass, t), NumArgs(numargs) {
|
|
|
|
SubExprs = new Expr*[numargs+1];
|
|
|
|
SubExprs[FN] = fn;
|
2007-07-11 21:01:13 +04:00
|
|
|
for (unsigned i = 0; i != numargs; ++i)
|
2007-08-24 22:13:47 +04:00
|
|
|
SubExprs[i+ARGS_START] = args[i];
|
2007-07-11 21:01:13 +04:00
|
|
|
RParenLoc = rparenloc;
|
|
|
|
}
|
|
|
|
|
2007-12-28 08:25:02 +03:00
|
|
|
/// 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(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)
|
|
|
|
delete getArg(i);
|
|
|
|
this->NumArgs = NumArgs;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Otherwise, we are growing the # arguments. New an bigger argument array.
|
|
|
|
Expr **NewSubExprs = new Expr*[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;
|
|
|
|
|
|
|
|
delete[] SubExprs;
|
|
|
|
SubExprs = NewSubExprs;
|
|
|
|
this->NumArgs = NumArgs;
|
|
|
|
}
|
|
|
|
|
2008-01-31 04:07:12 +03:00
|
|
|
bool CallExpr::isBuiltinConstantExpr() 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 false;
|
|
|
|
|
|
|
|
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
|
|
|
|
if (!DRE)
|
|
|
|
return false;
|
|
|
|
|
2008-01-31 05:13:57 +03:00
|
|
|
const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl());
|
|
|
|
if (!FDecl)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
unsigned builtinID = FDecl->getIdentifier()->getBuiltinID();
|
|
|
|
if (!builtinID)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// We have a builtin that is a constant expression
|
|
|
|
if (builtinID == Builtin::BI__builtin___CFStringMakeConstantString)
|
2008-01-31 04:07:12 +03:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
2007-12-28 08:25:02 +03:00
|
|
|
|
2007-08-09 02:15:55 +04:00
|
|
|
bool CallExpr::isBuiltinClassifyType(llvm::APSInt &Result) const {
|
|
|
|
// The following enum mimics gcc's internal "typeclass.h" file.
|
|
|
|
enum gcc_type_class {
|
|
|
|
no_type_class = -1,
|
|
|
|
void_type_class, integer_type_class, char_type_class,
|
|
|
|
enumeral_type_class, boolean_type_class,
|
|
|
|
pointer_type_class, reference_type_class, offset_type_class,
|
|
|
|
real_type_class, complex_type_class,
|
|
|
|
function_type_class, method_type_class,
|
|
|
|
record_type_class, union_type_class,
|
|
|
|
array_type_class, string_type_class,
|
|
|
|
lang_type_class
|
|
|
|
};
|
|
|
|
Result.setIsSigned(true);
|
|
|
|
|
|
|
|
// 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 false;
|
|
|
|
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
|
|
|
|
if (!DRE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// We have a DeclRefExpr.
|
|
|
|
if (strcmp(DRE->getDecl()->getName(), "__builtin_classify_type") == 0) {
|
|
|
|
// If no argument was supplied, default to "no_type_class". This isn't
|
|
|
|
// ideal, however it's what gcc does.
|
|
|
|
Result = static_cast<uint64_t>(no_type_class);
|
|
|
|
if (NumArgs >= 1) {
|
|
|
|
QualType argType = getArg(0)->getType();
|
|
|
|
|
|
|
|
if (argType->isVoidType())
|
|
|
|
Result = void_type_class;
|
|
|
|
else if (argType->isEnumeralType())
|
|
|
|
Result = enumeral_type_class;
|
|
|
|
else if (argType->isBooleanType())
|
|
|
|
Result = boolean_type_class;
|
|
|
|
else if (argType->isCharType())
|
|
|
|
Result = string_type_class; // gcc doesn't appear to use char_type_class
|
|
|
|
else if (argType->isIntegerType())
|
|
|
|
Result = integer_type_class;
|
|
|
|
else if (argType->isPointerType())
|
|
|
|
Result = pointer_type_class;
|
|
|
|
else if (argType->isReferenceType())
|
|
|
|
Result = reference_type_class;
|
|
|
|
else if (argType->isRealType())
|
|
|
|
Result = real_type_class;
|
|
|
|
else if (argType->isComplexType())
|
|
|
|
Result = complex_type_class;
|
|
|
|
else if (argType->isFunctionType())
|
|
|
|
Result = function_type_class;
|
|
|
|
else if (argType->isStructureType())
|
|
|
|
Result = record_type_class;
|
|
|
|
else if (argType->isUnionType())
|
|
|
|
Result = union_type_class;
|
|
|
|
else if (argType->isArrayType())
|
|
|
|
Result = array_type_class;
|
|
|
|
else if (argType->isUnionType())
|
|
|
|
Result = union_type_class;
|
|
|
|
else // FIXME: offset_type_class, method_type_class, & lang_type_class?
|
2007-11-08 20:56:40 +03:00
|
|
|
assert(0 && "CallExpr::isBuiltinClassifyType(): unimplemented type");
|
2007-08-09 02:15:55 +04:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
|
|
|
|
/// corresponds to, e.g. "<<=".
|
|
|
|
const char *BinaryOperator::getOpcodeStr(Opcode Op) {
|
|
|
|
switch (Op) {
|
|
|
|
default: assert(0 && "Unknown binary operator");
|
|
|
|
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 ",";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-31 08:56:16 +04:00
|
|
|
InitListExpr::InitListExpr(SourceLocation lbraceloc,
|
|
|
|
Expr **initexprs, unsigned numinits,
|
|
|
|
SourceLocation rbraceloc)
|
2008-05-01 06:04:18 +04:00
|
|
|
: Expr(InitListExprClass, QualType()),
|
|
|
|
LBraceLoc(lbraceloc), RBraceLoc(rbraceloc)
|
2007-08-31 08:56:16 +04:00
|
|
|
{
|
|
|
|
for (unsigned i = 0; i != numinits; i++)
|
2008-05-01 06:04:18 +04:00
|
|
|
InitExprs.push_back(initexprs[i]);
|
2007-08-31 08:56:16 +04:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Generic Expression Routines
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// hasLocalSideEffect - Return true if this immediate expression has side
|
|
|
|
/// effects, not counting any sub-expressions.
|
|
|
|
bool Expr::hasLocalSideEffect() const {
|
|
|
|
switch (getStmtClass()) {
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
case ParenExprClass:
|
|
|
|
return cast<ParenExpr>(this)->getSubExpr()->hasLocalSideEffect();
|
|
|
|
case UnaryOperatorClass: {
|
|
|
|
const UnaryOperator *UO = cast<UnaryOperator>(this);
|
|
|
|
|
|
|
|
switch (UO->getOpcode()) {
|
|
|
|
default: return false;
|
|
|
|
case UnaryOperator::PostInc:
|
|
|
|
case UnaryOperator::PostDec:
|
|
|
|
case UnaryOperator::PreInc:
|
|
|
|
case UnaryOperator::PreDec:
|
|
|
|
return true; // ++/--
|
|
|
|
|
|
|
|
case UnaryOperator::Deref:
|
|
|
|
// Dereferencing a volatile pointer is a side-effect.
|
|
|
|
return getType().isVolatileQualified();
|
|
|
|
case UnaryOperator::Real:
|
|
|
|
case UnaryOperator::Imag:
|
|
|
|
// accessing a piece of a volatile complex is a side-effect.
|
|
|
|
return UO->getSubExpr()->getType().isVolatileQualified();
|
|
|
|
|
|
|
|
case UnaryOperator::Extension:
|
|
|
|
return UO->getSubExpr()->hasLocalSideEffect();
|
|
|
|
}
|
|
|
|
}
|
2007-12-01 09:07:34 +03:00
|
|
|
case BinaryOperatorClass: {
|
|
|
|
const BinaryOperator *BinOp = cast<BinaryOperator>(this);
|
|
|
|
// Consider comma to have side effects if the LHS and RHS both do.
|
|
|
|
if (BinOp->getOpcode() == BinaryOperator::Comma)
|
|
|
|
return BinOp->getLHS()->hasLocalSideEffect() &&
|
|
|
|
BinOp->getRHS()->hasLocalSideEffect();
|
|
|
|
|
|
|
|
return BinOp->isAssignmentOp();
|
|
|
|
}
|
2007-08-25 06:00:02 +04:00
|
|
|
case CompoundAssignOperatorClass:
|
2007-08-25 05:55:00 +04:00
|
|
|
return true;
|
2007-07-11 21:01:13 +04:00
|
|
|
|
2007-12-01 22:58:28 +03:00
|
|
|
case ConditionalOperatorClass: {
|
|
|
|
const ConditionalOperator *Exp = cast<ConditionalOperator>(this);
|
|
|
|
return Exp->getCond()->hasLocalSideEffect()
|
|
|
|
|| (Exp->getLHS() && Exp->getLHS()->hasLocalSideEffect())
|
|
|
|
|| (Exp->getRHS() && Exp->getRHS()->hasLocalSideEffect());
|
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
case MemberExprClass:
|
|
|
|
case ArraySubscriptExprClass:
|
|
|
|
// If the base pointer or element is to a volatile pointer/field, accessing
|
|
|
|
// if is a side effect.
|
|
|
|
return getType().isVolatileQualified();
|
|
|
|
|
|
|
|
case CallExprClass:
|
|
|
|
// TODO: check attributes for pure/const. "void foo() { strlen("bar"); }"
|
|
|
|
// should warn.
|
|
|
|
return true;
|
2007-09-27 02:06:30 +04:00
|
|
|
case ObjCMessageExprClass:
|
|
|
|
return true;
|
2007-07-11 21:01:13 +04:00
|
|
|
|
|
|
|
case CastExprClass:
|
|
|
|
// 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()->hasLocalSideEffect();
|
|
|
|
return false;
|
2008-04-08 08:40:51 +04:00
|
|
|
|
|
|
|
case CXXDefaultArgExprClass:
|
|
|
|
return cast<CXXDefaultArgExpr>(this)->getExpr()->hasLocalSideEffect();
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// 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
|
2007-10-31 01:53:42 +03:00
|
|
|
/// - (__real__ e) and (__imag__ e) where e is an lvalue [GNU extension]
|
2007-07-17 07:52:31 +04:00
|
|
|
/// - reference type [C++ [expr]]
|
2007-07-11 21:01:13 +04:00
|
|
|
///
|
2007-07-16 11:07:56 +04:00
|
|
|
Expr::isLvalueResult Expr::isLvalue() const {
|
2007-07-11 21:01:13 +04:00
|
|
|
// first, check the type (C99 6.3.2.1)
|
2007-07-21 09:33:26 +04:00
|
|
|
if (TR->isFunctionType()) // from isObjectType()
|
2007-07-11 21:01:13 +04:00
|
|
|
return LV_NotObjectType;
|
|
|
|
|
2008-02-10 04:39:04 +03:00
|
|
|
// Allow qualified void which is an incomplete type other than void (yuck).
|
2008-02-20 23:55:12 +03:00
|
|
|
if (TR->isVoidType() && !TR.getCanonicalType().getCVRQualifiers())
|
2008-02-10 04:39:04 +03:00
|
|
|
return LV_IncompleteVoidType;
|
|
|
|
|
2007-07-21 09:33:26 +04:00
|
|
|
if (TR->isReferenceType()) // C++ [expr]
|
2007-07-17 07:52:31 +04:00
|
|
|
return LV_Valid;
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// the type looks fine, now check the expression
|
|
|
|
switch (getStmtClass()) {
|
|
|
|
case StringLiteralClass: // C99 6.5.1p4
|
2007-12-01 01:47:59 +03:00
|
|
|
return LV_Valid;
|
2007-07-11 21:01:13 +04:00
|
|
|
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();
|
|
|
|
return LV_Valid;
|
|
|
|
case DeclRefExprClass: // C99 6.5.1p2
|
|
|
|
if (isa<VarDecl>(cast<DeclRefExpr>(this)->getDecl()))
|
|
|
|
return LV_Valid;
|
|
|
|
break;
|
2007-07-12 19:26:50 +04:00
|
|
|
case MemberExprClass: { // C99 6.5.2.3p4
|
2007-07-11 21:01:13 +04:00
|
|
|
const MemberExpr *m = cast<MemberExpr>(this);
|
|
|
|
return m->isArrow() ? LV_Valid : m->getBase()->isLvalue();
|
2007-07-12 19:26:50 +04:00
|
|
|
}
|
2007-10-31 01:53:42 +03:00
|
|
|
case UnaryOperatorClass:
|
2007-07-11 21:01:13 +04:00
|
|
|
if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref)
|
2007-10-31 01:53:42 +03:00
|
|
|
return LV_Valid; // C99 6.5.3p4
|
|
|
|
|
|
|
|
if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Real ||
|
|
|
|
cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Imag)
|
|
|
|
return cast<UnaryOperator>(this)->getSubExpr()->isLvalue(); // GNU.
|
2007-07-11 21:01:13 +04:00
|
|
|
break;
|
|
|
|
case ParenExprClass: // C99 6.5.1p5
|
|
|
|
return cast<ParenExpr>(this)->getSubExpr()->isLvalue();
|
2007-12-05 07:00:10 +03:00
|
|
|
case CompoundLiteralExprClass: // C99 6.5.2.5p5
|
|
|
|
return LV_Valid;
|
2008-04-19 03:10:10 +04:00
|
|
|
case ExtVectorElementExprClass:
|
|
|
|
if (cast<ExtVectorElementExpr>(this)->containsDuplicateElements())
|
2007-07-30 07:29:09 +04:00
|
|
|
return LV_DuplicateVectorComponents;
|
|
|
|
return LV_Valid;
|
2007-11-12 17:34:27 +03:00
|
|
|
case ObjCIvarRefExprClass: // ObjC instance variables are lvalues.
|
|
|
|
return LV_Valid;
|
2008-01-12 11:14:25 +03:00
|
|
|
case PreDefinedExprClass:
|
|
|
|
return LV_Valid;
|
2008-04-08 08:40:51 +04:00
|
|
|
case CXXDefaultArgExprClass:
|
|
|
|
return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue();
|
2007-07-11 21:01:13 +04:00
|
|
|
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.
|
2007-07-16 11:07:56 +04:00
|
|
|
Expr::isModifiableLvalueResult Expr::isModifiableLvalue() const {
|
2007-07-11 21:01:13 +04:00
|
|
|
isLvalueResult lvalResult = isLvalue();
|
|
|
|
|
|
|
|
switch (lvalResult) {
|
|
|
|
case LV_Valid: break;
|
|
|
|
case LV_NotObjectType: return MLV_NotObjectType;
|
|
|
|
case LV_IncompleteVoidType: return MLV_IncompleteVoidType;
|
2007-07-30 07:29:09 +04:00
|
|
|
case LV_DuplicateVectorComponents: return MLV_DuplicateVectorComponents;
|
2007-07-11 21:01:13 +04:00
|
|
|
case LV_InvalidExpression: return MLV_InvalidExpression;
|
|
|
|
}
|
|
|
|
if (TR.isConstQualified())
|
|
|
|
return MLV_ConstQualified;
|
|
|
|
if (TR->isArrayType())
|
|
|
|
return MLV_ArrayType;
|
|
|
|
if (TR->isIncompleteType())
|
|
|
|
return MLV_IncompleteType;
|
|
|
|
|
|
|
|
if (const RecordType *r = dyn_cast<RecordType>(TR.getCanonicalType())) {
|
|
|
|
if (r->hasConstFields())
|
|
|
|
return MLV_ConstQualified;
|
|
|
|
}
|
|
|
|
return MLV_Valid;
|
|
|
|
}
|
|
|
|
|
2008-02-27 21:39:48 +03:00
|
|
|
/// hasGlobalStorage - Return true if this expression has static storage
|
2007-11-28 00:35:27 +03:00
|
|
|
/// duration. This means that the address of this expression is a link-time
|
|
|
|
/// constant.
|
2008-02-27 21:39:48 +03:00
|
|
|
bool Expr::hasGlobalStorage() const {
|
2007-11-13 21:05:45 +03:00
|
|
|
switch (getStmtClass()) {
|
|
|
|
default:
|
|
|
|
return false;
|
2007-11-28 00:35:27 +03:00
|
|
|
case ParenExprClass:
|
2008-02-27 21:39:48 +03:00
|
|
|
return cast<ParenExpr>(this)->getSubExpr()->hasGlobalStorage();
|
2007-11-28 00:35:27 +03:00
|
|
|
case ImplicitCastExprClass:
|
2008-02-27 21:39:48 +03:00
|
|
|
return cast<ImplicitCastExpr>(this)->getSubExpr()->hasGlobalStorage();
|
2008-01-14 21:19:28 +03:00
|
|
|
case CompoundLiteralExprClass:
|
|
|
|
return cast<CompoundLiteralExpr>(this)->isFileScope();
|
2007-11-13 21:05:45 +03:00
|
|
|
case DeclRefExprClass: {
|
|
|
|
const Decl *D = cast<DeclRefExpr>(this)->getDecl();
|
|
|
|
if (const VarDecl *VD = dyn_cast<VarDecl>(D))
|
2008-02-27 21:39:48 +03:00
|
|
|
return VD->hasGlobalStorage();
|
2008-04-04 13:45:30 +04:00
|
|
|
if (isa<FunctionDecl>(D))
|
|
|
|
return true;
|
2007-11-13 21:05:45 +03:00
|
|
|
return false;
|
|
|
|
}
|
2007-11-28 07:30:09 +03:00
|
|
|
case MemberExprClass: {
|
2007-11-13 21:05:45 +03:00
|
|
|
const MemberExpr *M = cast<MemberExpr>(this);
|
2008-02-27 21:39:48 +03:00
|
|
|
return !M->isArrow() && M->getBase()->hasGlobalStorage();
|
2007-11-28 07:30:09 +03:00
|
|
|
}
|
2007-11-28 00:35:27 +03:00
|
|
|
case ArraySubscriptExprClass:
|
2008-02-27 21:39:48 +03:00
|
|
|
return cast<ArraySubscriptExpr>(this)->getBase()->hasGlobalStorage();
|
2008-01-12 11:14:25 +03:00
|
|
|
case PreDefinedExprClass:
|
|
|
|
return true;
|
2008-04-08 08:40:51 +04:00
|
|
|
case CXXDefaultArgExprClass:
|
|
|
|
return cast<CXXDefaultArgExpr>(this)->getExpr()->hasGlobalStorage();
|
2007-11-13 21:05:45 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-17 19:57:34 +03:00
|
|
|
Expr* Expr::IgnoreParens() {
|
|
|
|
Expr* E = this;
|
|
|
|
while (ParenExpr* P = dyn_cast<ParenExpr>(E))
|
|
|
|
E = P->getSubExpr();
|
|
|
|
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
|
2008-02-13 04:02:39 +03:00
|
|
|
/// 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 if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E))
|
|
|
|
E = P->getSubExpr();
|
|
|
|
else
|
|
|
|
return E;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-09-03 00:30:18 +04:00
|
|
|
bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const {
|
|
|
|
switch (getStmtClass()) {
|
|
|
|
default:
|
|
|
|
if (Loc) *Loc = getLocStart();
|
|
|
|
return false;
|
|
|
|
case ParenExprClass:
|
|
|
|
return cast<ParenExpr>(this)->getSubExpr()->isConstantExpr(Ctx, Loc);
|
|
|
|
case StringLiteralClass:
|
2007-11-09 18:00:03 +03:00
|
|
|
case ObjCStringLiteralClass:
|
2007-09-03 00:30:18 +04:00
|
|
|
case FloatingLiteralClass:
|
|
|
|
case IntegerLiteralClass:
|
|
|
|
case CharacterLiteralClass:
|
|
|
|
case ImaginaryLiteralClass:
|
2007-10-17 04:52:43 +04:00
|
|
|
case TypesCompatibleExprClass:
|
|
|
|
case CXXBoolLiteralExprClass:
|
2007-10-18 04:20:32 +04:00
|
|
|
return true;
|
2007-09-03 00:30:18 +04:00
|
|
|
case CallExprClass: {
|
|
|
|
const CallExpr *CE = cast<CallExpr>(this);
|
|
|
|
llvm::APSInt Result(32);
|
2008-03-05 21:54:05 +03:00
|
|
|
Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType())));
|
2007-09-03 00:30:18 +04:00
|
|
|
if (CE->isBuiltinClassifyType(Result))
|
2007-10-18 04:20:32 +04:00
|
|
|
return true;
|
2008-01-31 04:07:12 +03:00
|
|
|
if (CE->isBuiltinConstantExpr())
|
|
|
|
return true;
|
2007-09-03 00:30:18 +04:00
|
|
|
if (Loc) *Loc = getLocStart();
|
|
|
|
return false;
|
|
|
|
}
|
2007-11-01 05:45:17 +03:00
|
|
|
case DeclRefExprClass: {
|
|
|
|
const Decl *D = cast<DeclRefExpr>(this)->getDecl();
|
|
|
|
// Accept address of function.
|
|
|
|
if (isa<EnumConstantDecl>(D) || isa<FunctionDecl>(D))
|
2007-10-18 04:20:32 +04:00
|
|
|
return true;
|
2007-09-03 00:30:18 +04:00
|
|
|
if (Loc) *Loc = getLocStart();
|
2007-11-13 21:05:45 +03:00
|
|
|
if (isa<VarDecl>(D))
|
|
|
|
return TR->isArrayType();
|
2007-09-03 00:30:18 +04:00
|
|
|
return false;
|
2007-11-01 05:45:17 +03:00
|
|
|
}
|
2008-01-09 03:05:37 +03:00
|
|
|
case CompoundLiteralExprClass:
|
|
|
|
if (Loc) *Loc = getLocStart();
|
|
|
|
// Allow "(int []){2,4}", since the array will be converted to a pointer.
|
2008-01-25 08:34:48 +03:00
|
|
|
// Allow "(vector type){2,4}" since the elements are all constant.
|
|
|
|
return TR->isArrayType() || TR->isVectorType();
|
2007-09-03 00:30:18 +04:00
|
|
|
case UnaryOperatorClass: {
|
|
|
|
const UnaryOperator *Exp = cast<UnaryOperator>(this);
|
|
|
|
|
2007-11-13 21:05:45 +03:00
|
|
|
// C99 6.6p9
|
2007-12-12 02:11:17 +03:00
|
|
|
if (Exp->getOpcode() == UnaryOperator::AddrOf) {
|
2008-02-27 21:39:48 +03:00
|
|
|
if (!Exp->getSubExpr()->hasGlobalStorage()) {
|
2007-12-12 02:11:17 +03:00
|
|
|
if (Loc) *Loc = getLocStart();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2007-11-13 21:05:45 +03:00
|
|
|
|
2007-09-03 00:30:18 +04:00
|
|
|
// Get the operand value. If this is sizeof/alignof, do not evalute the
|
|
|
|
// operand. This affects C99 6.6p3.
|
2008-01-11 01:15:12 +03:00
|
|
|
if (!Exp->isSizeOfAlignOfOp() &&
|
|
|
|
Exp->getOpcode() != UnaryOperator::OffsetOf &&
|
2007-09-03 00:30:18 +04:00
|
|
|
!Exp->getSubExpr()->isConstantExpr(Ctx, Loc))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (Exp->getOpcode()) {
|
|
|
|
// Address, indirect, pre/post inc/dec, etc are not valid constant exprs.
|
|
|
|
// See C99 6.6p3.
|
|
|
|
default:
|
|
|
|
if (Loc) *Loc = Exp->getOperatorLoc();
|
|
|
|
return false;
|
|
|
|
case UnaryOperator::Extension:
|
|
|
|
return true; // FIXME: this is wrong.
|
|
|
|
case UnaryOperator::SizeOf:
|
|
|
|
case UnaryOperator::AlignOf:
|
2008-01-11 01:15:12 +03:00
|
|
|
case UnaryOperator::OffsetOf:
|
2007-09-03 00:30:18 +04:00
|
|
|
// sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
|
2008-02-15 15:20:59 +03:00
|
|
|
if (!Exp->getSubExpr()->getType()->isConstantSizeType()) {
|
2007-12-18 10:15:40 +03:00
|
|
|
if (Loc) *Loc = Exp->getOperatorLoc();
|
2007-09-03 00:30:18 +04:00
|
|
|
return false;
|
2007-12-18 10:15:40 +03:00
|
|
|
}
|
2007-10-18 04:20:32 +04:00
|
|
|
return true;
|
2007-09-03 00:30:18 +04:00
|
|
|
case UnaryOperator::LNot:
|
|
|
|
case UnaryOperator::Plus:
|
|
|
|
case UnaryOperator::Minus:
|
|
|
|
case UnaryOperator::Not:
|
2007-10-18 04:20:32 +04:00
|
|
|
return true;
|
2007-09-03 00:30:18 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case SizeOfAlignOfTypeExprClass: {
|
|
|
|
const SizeOfAlignOfTypeExpr *Exp = cast<SizeOfAlignOfTypeExpr>(this);
|
|
|
|
// alignof always evaluates to a constant.
|
2008-02-21 08:45:29 +03:00
|
|
|
if (Exp->isSizeOf() && !Exp->getArgumentType()->isVoidType() &&
|
|
|
|
!Exp->getArgumentType()->isConstantSizeType()) {
|
2007-12-18 10:15:40 +03:00
|
|
|
if (Loc) *Loc = Exp->getOperatorLoc();
|
2007-09-03 00:30:18 +04:00
|
|
|
return false;
|
2007-12-18 10:15:40 +03:00
|
|
|
}
|
2007-10-18 04:20:32 +04:00
|
|
|
return true;
|
2007-09-03 00:30:18 +04:00
|
|
|
}
|
|
|
|
case BinaryOperatorClass: {
|
|
|
|
const BinaryOperator *Exp = cast<BinaryOperator>(this);
|
|
|
|
|
|
|
|
// The LHS of a constant expr is always evaluated and needed.
|
|
|
|
if (!Exp->getLHS()->isConstantExpr(Ctx, Loc))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (!Exp->getRHS()->isConstantExpr(Ctx, Loc))
|
|
|
|
return false;
|
2007-10-18 04:20:32 +04:00
|
|
|
return true;
|
2007-09-03 00:30:18 +04:00
|
|
|
}
|
|
|
|
case ImplicitCastExprClass:
|
|
|
|
case CastExprClass: {
|
|
|
|
const Expr *SubExpr;
|
|
|
|
SourceLocation CastLoc;
|
|
|
|
if (const CastExpr *C = dyn_cast<CastExpr>(this)) {
|
|
|
|
SubExpr = C->getSubExpr();
|
|
|
|
CastLoc = C->getLParenLoc();
|
|
|
|
} else {
|
|
|
|
SubExpr = cast<ImplicitCastExpr>(this)->getSubExpr();
|
|
|
|
CastLoc = getLocStart();
|
|
|
|
}
|
|
|
|
if (!SubExpr->isConstantExpr(Ctx, Loc)) {
|
|
|
|
if (Loc) *Loc = SubExpr->getLocStart();
|
|
|
|
return false;
|
|
|
|
}
|
2007-10-18 04:20:32 +04:00
|
|
|
return true;
|
2007-09-03 00:30:18 +04:00
|
|
|
}
|
|
|
|
case ConditionalOperatorClass: {
|
|
|
|
const ConditionalOperator *Exp = cast<ConditionalOperator>(this);
|
2007-10-18 04:20:32 +04:00
|
|
|
if (!Exp->getCond()->isConstantExpr(Ctx, Loc) ||
|
2007-11-30 22:04:31 +03:00
|
|
|
// Handle the GNU extension for missing LHS.
|
|
|
|
!(Exp->getLHS() && Exp->getLHS()->isConstantExpr(Ctx, Loc)) ||
|
2007-10-18 04:20:32 +04:00
|
|
|
!Exp->getRHS()->isConstantExpr(Ctx, Loc))
|
2007-09-03 00:30:18 +04:00
|
|
|
return false;
|
2007-10-18 04:20:32 +04:00
|
|
|
return true;
|
2007-09-03 00:30:18 +04:00
|
|
|
}
|
2008-01-11 01:15:12 +03:00
|
|
|
case InitListExprClass: {
|
|
|
|
const InitListExpr *Exp = cast<InitListExpr>(this);
|
|
|
|
unsigned numInits = Exp->getNumInits();
|
|
|
|
for (unsigned i = 0; i < numInits; i++) {
|
|
|
|
if (!Exp->getInit(i)->isConstantExpr(Ctx, Loc)) {
|
|
|
|
if (Loc) *Loc = Exp->getInit(i)->getLocStart();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2008-04-08 08:40:51 +04:00
|
|
|
case CXXDefaultArgExprClass:
|
|
|
|
return cast<CXXDefaultArgExpr>(this)->getExpr()->isConstantExpr(Ctx, Loc);
|
2007-09-03 00:30:18 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
/// isIntegerConstantExpr - this recursive routine will test if an expression is
|
|
|
|
/// an integer constant expression. Note: With the introduction of VLA's in
|
|
|
|
/// C99 the result of the sizeof operator is no longer always a constant
|
|
|
|
/// expression. The generalization of the wording to include any subexpression
|
|
|
|
/// that is not evaluated (C99 6.6p3) means that nonconstant subexpressions
|
|
|
|
/// can appear as operands to other operators (e.g. &&, ||, ?:). For instance,
|
|
|
|
/// "0 || f()" can be treated as a constant expression. In C90 this expression,
|
|
|
|
/// occurring in a context requiring a constant, would have been a constraint
|
|
|
|
/// violation. FIXME: This routine currently implements C90 semantics.
|
|
|
|
/// To properly implement C99 semantics this routine will need to evaluate
|
|
|
|
/// expressions involving operators previously mentioned.
|
|
|
|
|
|
|
|
/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero,
|
|
|
|
/// comma, etc
|
|
|
|
///
|
|
|
|
/// FIXME: This should ext-warn on overflow during evaluation! ISO C does not
|
2007-09-26 04:47:26 +04:00
|
|
|
/// permit this. This includes things like (int)1e1000
|
2007-07-18 09:21:20 +04:00
|
|
|
///
|
|
|
|
/// 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.
|
2007-07-16 03:26:56 +04:00
|
|
|
bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
|
|
|
|
SourceLocation *Loc, bool isEvaluated) const {
|
2007-07-11 21:01:13 +04:00
|
|
|
switch (getStmtClass()) {
|
|
|
|
default:
|
|
|
|
if (Loc) *Loc = getLocStart();
|
|
|
|
return false;
|
|
|
|
case ParenExprClass:
|
|
|
|
return cast<ParenExpr>(this)->getSubExpr()->
|
2007-07-16 03:26:56 +04:00
|
|
|
isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated);
|
2007-07-11 21:01:13 +04:00
|
|
|
case IntegerLiteralClass:
|
|
|
|
Result = cast<IntegerLiteral>(this)->getValue();
|
|
|
|
break;
|
2007-07-16 03:32:58 +04:00
|
|
|
case CharacterLiteralClass: {
|
|
|
|
const CharacterLiteral *CL = cast<CharacterLiteral>(this);
|
2008-03-05 21:54:05 +03:00
|
|
|
Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType())));
|
2007-07-16 03:32:58 +04:00
|
|
|
Result = CL->getValue();
|
2007-07-17 01:04:56 +04:00
|
|
|
Result.setIsUnsigned(!getType()->isSignedIntegerType());
|
2007-07-11 21:01:13 +04:00
|
|
|
break;
|
2007-07-16 03:32:58 +04:00
|
|
|
}
|
2007-08-02 08:09:23 +04:00
|
|
|
case TypesCompatibleExprClass: {
|
|
|
|
const TypesCompatibleExpr *TCE = cast<TypesCompatibleExpr>(this);
|
2008-03-05 21:54:05 +03:00
|
|
|
Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType())));
|
2007-10-16 00:41:53 +04:00
|
|
|
Result = Ctx.typesAreCompatible(TCE->getArgType1(), TCE->getArgType2());
|
2007-08-02 04:13:27 +04:00
|
|
|
break;
|
2007-08-02 08:09:23 +04:00
|
|
|
}
|
2007-08-09 02:15:55 +04:00
|
|
|
case CallExprClass: {
|
|
|
|
const CallExpr *CE = cast<CallExpr>(this);
|
2008-03-05 21:54:05 +03:00
|
|
|
Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType())));
|
2007-08-09 02:15:55 +04:00
|
|
|
if (CE->isBuiltinClassifyType(Result))
|
|
|
|
break;
|
|
|
|
if (Loc) *Loc = getLocStart();
|
|
|
|
return false;
|
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
case DeclRefExprClass:
|
|
|
|
if (const EnumConstantDecl *D =
|
|
|
|
dyn_cast<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl())) {
|
|
|
|
Result = D->getInitVal();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (Loc) *Loc = getLocStart();
|
|
|
|
return false;
|
|
|
|
case UnaryOperatorClass: {
|
|
|
|
const UnaryOperator *Exp = cast<UnaryOperator>(this);
|
|
|
|
|
|
|
|
// Get the operand value. If this is sizeof/alignof, do not evalute the
|
|
|
|
// operand. This affects C99 6.6p3.
|
2008-01-29 18:56:48 +03:00
|
|
|
if (!Exp->isSizeOfAlignOfOp() && !Exp->isOffsetOfOp() &&
|
2007-08-24 01:42:50 +04:00
|
|
|
!Exp->getSubExpr()->isIntegerConstantExpr(Result, Ctx, Loc,isEvaluated))
|
2007-07-11 21:01:13 +04:00
|
|
|
return false;
|
|
|
|
|
|
|
|
switch (Exp->getOpcode()) {
|
|
|
|
// Address, indirect, pre/post inc/dec, etc are not valid constant exprs.
|
|
|
|
// See C99 6.6p3.
|
|
|
|
default:
|
|
|
|
if (Loc) *Loc = Exp->getOperatorLoc();
|
|
|
|
return false;
|
|
|
|
case UnaryOperator::Extension:
|
2007-07-18 22:38:36 +04:00
|
|
|
return true; // FIXME: this is wrong.
|
2007-07-11 21:01:13 +04:00
|
|
|
case UnaryOperator::SizeOf:
|
|
|
|
case UnaryOperator::AlignOf:
|
2008-02-21 08:45:29 +03:00
|
|
|
// Return the result in the right width.
|
2008-03-05 21:54:05 +03:00
|
|
|
Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType())));
|
2008-02-21 08:45:29 +03:00
|
|
|
|
|
|
|
// sizeof(void) and __alignof__(void) = 1 as a gcc extension.
|
|
|
|
if (Exp->getSubExpr()->getType()->isVoidType()) {
|
|
|
|
Result = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
|
2008-02-15 15:20:59 +03:00
|
|
|
if (!Exp->getSubExpr()->getType()->isConstantSizeType()) {
|
2007-12-18 10:15:40 +03:00
|
|
|
if (Loc) *Loc = Exp->getOperatorLoc();
|
2007-07-11 21:01:13 +04:00
|
|
|
return false;
|
2007-12-18 10:15:40 +03:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
|
2007-07-18 22:38:36 +04:00
|
|
|
// Get information about the size or align.
|
2008-01-03 00:54:09 +03:00
|
|
|
if (Exp->getSubExpr()->getType()->isFunctionType()) {
|
|
|
|
// GCC extension: sizeof(function) = 1.
|
|
|
|
Result = Exp->getOpcode() == UnaryOperator::AlignOf ? 4 : 1;
|
2007-11-27 21:22:04 +03:00
|
|
|
} else {
|
2008-03-05 21:54:05 +03:00
|
|
|
unsigned CharSize = Ctx.Target.getCharWidth();
|
2008-02-18 10:10:45 +03:00
|
|
|
if (Exp->getOpcode() == UnaryOperator::AlignOf)
|
2008-03-05 21:54:05 +03:00
|
|
|
Result = Ctx.getTypeAlign(Exp->getSubExpr()->getType()) / CharSize;
|
2008-02-18 10:10:45 +03:00
|
|
|
else
|
2008-03-05 21:54:05 +03:00
|
|
|
Result = Ctx.getTypeSize(Exp->getSubExpr()->getType()) / CharSize;
|
2007-11-27 21:22:04 +03:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
break;
|
|
|
|
case UnaryOperator::LNot: {
|
2008-01-25 22:16:19 +03:00
|
|
|
bool Val = Result == 0;
|
2008-03-05 21:54:05 +03:00
|
|
|
Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType())));
|
2007-07-11 21:01:13 +04:00
|
|
|
Result = Val;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case UnaryOperator::Plus:
|
|
|
|
break;
|
|
|
|
case UnaryOperator::Minus:
|
|
|
|
Result = -Result;
|
|
|
|
break;
|
|
|
|
case UnaryOperator::Not:
|
|
|
|
Result = ~Result;
|
|
|
|
break;
|
2008-01-29 18:56:48 +03:00
|
|
|
case UnaryOperator::OffsetOf:
|
|
|
|
Result = Exp->evaluateOffsetOf(Ctx);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SizeOfAlignOfTypeExprClass: {
|
|
|
|
const SizeOfAlignOfTypeExpr *Exp = cast<SizeOfAlignOfTypeExpr>(this);
|
2008-02-21 08:45:29 +03:00
|
|
|
|
|
|
|
// Return the result in the right width.
|
2008-03-05 21:54:05 +03:00
|
|
|
Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType())));
|
2008-02-21 08:45:29 +03:00
|
|
|
|
|
|
|
// sizeof(void) and __alignof__(void) = 1 as a gcc extension.
|
|
|
|
if (Exp->getArgumentType()->isVoidType()) {
|
|
|
|
Result = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// alignof always evaluates to a constant, sizeof does if arg is not VLA.
|
2008-02-15 15:20:59 +03:00
|
|
|
if (Exp->isSizeOf() && !Exp->getArgumentType()->isConstantSizeType()) {
|
2007-12-18 10:15:40 +03:00
|
|
|
if (Loc) *Loc = Exp->getOperatorLoc();
|
2007-07-11 21:01:13 +04:00
|
|
|
return false;
|
2007-12-18 10:15:40 +03:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
|
2007-07-18 22:38:36 +04:00
|
|
|
// Get information about the size or align.
|
2008-01-03 00:54:09 +03:00
|
|
|
if (Exp->getArgumentType()->isFunctionType()) {
|
|
|
|
// GCC extension: sizeof(function) = 1.
|
|
|
|
Result = Exp->isSizeOf() ? 1 : 4;
|
2008-02-16 04:20:23 +03:00
|
|
|
} else {
|
2008-03-05 21:54:05 +03:00
|
|
|
unsigned CharSize = Ctx.Target.getCharWidth();
|
2008-02-16 04:20:23 +03:00
|
|
|
if (Exp->isSizeOf())
|
2008-03-05 21:54:05 +03:00
|
|
|
Result = Ctx.getTypeSize(Exp->getArgumentType()) / CharSize;
|
2008-02-16 04:20:23 +03:00
|
|
|
else
|
2008-03-05 21:54:05 +03:00
|
|
|
Result = Ctx.getTypeAlign(Exp->getArgumentType()) / CharSize;
|
2007-12-17 20:38:43 +03:00
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BinaryOperatorClass: {
|
|
|
|
const BinaryOperator *Exp = cast<BinaryOperator>(this);
|
|
|
|
|
|
|
|
// The LHS of a constant expr is always evaluated and needed.
|
2007-07-16 03:26:56 +04:00
|
|
|
if (!Exp->getLHS()->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated))
|
2007-07-11 21:01:13 +04:00
|
|
|
return false;
|
|
|
|
|
|
|
|
llvm::APSInt RHS(Result);
|
|
|
|
|
|
|
|
// The short-circuiting &&/|| operators don't necessarily evaluate their
|
|
|
|
// RHS. Make sure to pass isEvaluated down correctly.
|
|
|
|
if (Exp->isLogicalOp()) {
|
|
|
|
bool RHSEval;
|
|
|
|
if (Exp->getOpcode() == BinaryOperator::LAnd)
|
|
|
|
RHSEval = Result != 0;
|
|
|
|
else {
|
|
|
|
assert(Exp->getOpcode() == BinaryOperator::LOr &&"Unexpected logical");
|
|
|
|
RHSEval = Result == 0;
|
|
|
|
}
|
|
|
|
|
2007-07-16 03:26:56 +04:00
|
|
|
if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Ctx, Loc,
|
2007-07-11 21:01:13 +04:00
|
|
|
isEvaluated & RHSEval))
|
|
|
|
return false;
|
|
|
|
} else {
|
2007-07-16 03:26:56 +04:00
|
|
|
if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Ctx, Loc, isEvaluated))
|
2007-07-11 21:01:13 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (Exp->getOpcode()) {
|
|
|
|
default:
|
|
|
|
if (Loc) *Loc = getLocStart();
|
|
|
|
return false;
|
|
|
|
case BinaryOperator::Mul:
|
|
|
|
Result *= RHS;
|
|
|
|
break;
|
|
|
|
case BinaryOperator::Div:
|
|
|
|
if (RHS == 0) {
|
|
|
|
if (!isEvaluated) break;
|
|
|
|
if (Loc) *Loc = getLocStart();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Result /= RHS;
|
|
|
|
break;
|
|
|
|
case BinaryOperator::Rem:
|
|
|
|
if (RHS == 0) {
|
|
|
|
if (!isEvaluated) break;
|
|
|
|
if (Loc) *Loc = getLocStart();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Result %= RHS;
|
|
|
|
break;
|
|
|
|
case BinaryOperator::Add: Result += RHS; break;
|
|
|
|
case BinaryOperator::Sub: Result -= RHS; break;
|
|
|
|
case BinaryOperator::Shl:
|
2007-09-04 06:45:27 +04:00
|
|
|
Result <<=
|
|
|
|
static_cast<uint32_t>(RHS.getLimitedValue(Result.getBitWidth()-1));
|
2007-07-11 21:01:13 +04:00
|
|
|
break;
|
|
|
|
case BinaryOperator::Shr:
|
2007-09-04 06:45:27 +04:00
|
|
|
Result >>=
|
|
|
|
static_cast<uint32_t>(RHS.getLimitedValue(Result.getBitWidth()-1));
|
2007-07-11 21:01:13 +04:00
|
|
|
break;
|
|
|
|
case BinaryOperator::LT: Result = Result < RHS; break;
|
|
|
|
case BinaryOperator::GT: Result = Result > RHS; break;
|
|
|
|
case BinaryOperator::LE: Result = Result <= RHS; break;
|
|
|
|
case BinaryOperator::GE: Result = Result >= RHS; break;
|
|
|
|
case BinaryOperator::EQ: Result = Result == RHS; break;
|
|
|
|
case BinaryOperator::NE: Result = Result != RHS; break;
|
|
|
|
case BinaryOperator::And: Result &= RHS; break;
|
|
|
|
case BinaryOperator::Xor: Result ^= RHS; break;
|
|
|
|
case BinaryOperator::Or: Result |= RHS; break;
|
|
|
|
case BinaryOperator::LAnd:
|
|
|
|
Result = Result != 0 && RHS != 0;
|
|
|
|
break;
|
|
|
|
case BinaryOperator::LOr:
|
|
|
|
Result = Result != 0 || RHS != 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case BinaryOperator::Comma:
|
|
|
|
// C99 6.6p3: "shall not contain assignment, ..., or comma operators,
|
|
|
|
// *except* when they are contained within a subexpression that is not
|
|
|
|
// evaluated". Note that Assignment can never happen due to constraints
|
|
|
|
// on the LHS subexpr, so we don't need to check it here.
|
|
|
|
if (isEvaluated) {
|
|
|
|
if (Loc) *Loc = getLocStart();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The result of the constant expr is the RHS.
|
|
|
|
Result = RHS;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(!Exp->isAssignmentOp() && "LHS can't be a constant expr!");
|
|
|
|
break;
|
|
|
|
}
|
2007-07-16 03:54:50 +04:00
|
|
|
case ImplicitCastExprClass:
|
2007-07-11 21:01:13 +04:00
|
|
|
case CastExprClass: {
|
2007-07-16 03:54:50 +04:00
|
|
|
const Expr *SubExpr;
|
|
|
|
SourceLocation CastLoc;
|
|
|
|
if (const CastExpr *C = dyn_cast<CastExpr>(this)) {
|
|
|
|
SubExpr = C->getSubExpr();
|
|
|
|
CastLoc = C->getLParenLoc();
|
|
|
|
} else {
|
|
|
|
SubExpr = cast<ImplicitCastExpr>(this)->getSubExpr();
|
|
|
|
CastLoc = getLocStart();
|
|
|
|
}
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// C99 6.6p6: shall only convert arithmetic types to integer types.
|
2007-07-16 03:54:50 +04:00
|
|
|
if (!SubExpr->getType()->isArithmeticType() ||
|
|
|
|
!getType()->isIntegerType()) {
|
|
|
|
if (Loc) *Loc = SubExpr->getLocStart();
|
2007-07-11 21:01:13 +04:00
|
|
|
return false;
|
|
|
|
}
|
2007-09-22 23:04:13 +04:00
|
|
|
|
2008-03-05 21:54:05 +03:00
|
|
|
uint32_t DestWidth = static_cast<uint32_t>(Ctx.getTypeSize(getType()));
|
2007-09-22 23:04:13 +04:00
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// Handle simple integer->integer casts.
|
2007-07-16 03:54:50 +04:00
|
|
|
if (SubExpr->getType()->isIntegerType()) {
|
|
|
|
if (!SubExpr->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated))
|
2007-07-11 21:01:13 +04:00
|
|
|
return false;
|
2007-07-16 03:54:50 +04:00
|
|
|
|
|
|
|
// Figure out if this is a truncate, extend or noop cast.
|
|
|
|
// If the input is signed, do a sign extend, noop, or truncate.
|
2008-01-09 21:59:34 +03:00
|
|
|
if (getType()->isBooleanType()) {
|
|
|
|
// Conversion to bool compares against zero.
|
|
|
|
Result = Result != 0;
|
|
|
|
Result.zextOrTrunc(DestWidth);
|
|
|
|
} else if (SubExpr->getType()->isSignedIntegerType())
|
2007-07-16 03:54:50 +04:00
|
|
|
Result.sextOrTrunc(DestWidth);
|
|
|
|
else // If the input is unsigned, do a zero extend, noop, or truncate.
|
|
|
|
Result.zextOrTrunc(DestWidth);
|
2007-07-11 21:01:13 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Allow floating constants that are the immediate operands of casts or that
|
|
|
|
// are parenthesized.
|
2007-07-16 03:54:50 +04:00
|
|
|
const Expr *Operand = SubExpr;
|
2007-07-11 21:01:13 +04:00
|
|
|
while (const ParenExpr *PE = dyn_cast<ParenExpr>(Operand))
|
|
|
|
Operand = PE->getSubExpr();
|
2007-09-22 23:04:13 +04:00
|
|
|
|
|
|
|
// If this isn't a floating literal, we can't handle it.
|
|
|
|
const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(Operand);
|
|
|
|
if (!FL) {
|
|
|
|
if (Loc) *Loc = Operand->getLocStart();
|
|
|
|
return false;
|
|
|
|
}
|
2008-01-09 21:59:34 +03:00
|
|
|
|
|
|
|
// If the destination is boolean, compare against zero.
|
|
|
|
if (getType()->isBooleanType()) {
|
|
|
|
Result = !FL->getValue().isZero();
|
|
|
|
Result.zextOrTrunc(DestWidth);
|
|
|
|
break;
|
|
|
|
}
|
2007-07-11 21:01:13 +04:00
|
|
|
|
2007-09-22 23:04:13 +04:00
|
|
|
// Determine whether we are converting to unsigned or signed.
|
|
|
|
bool DestSigned = getType()->isSignedIntegerType();
|
2007-09-26 04:47:26 +04:00
|
|
|
|
|
|
|
// TODO: Warn on overflow, but probably not here: isIntegerConstantExpr can
|
|
|
|
// be called multiple times per AST.
|
2007-09-22 23:04:13 +04:00
|
|
|
uint64_t Space[4];
|
2007-09-26 04:47:26 +04:00
|
|
|
(void)FL->getValue().convertToInteger(Space, DestWidth, DestSigned,
|
|
|
|
llvm::APFloat::rmTowardZero);
|
2007-09-22 23:04:13 +04:00
|
|
|
Result = llvm::APInt(DestWidth, 4, Space);
|
|
|
|
break;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
case ConditionalOperatorClass: {
|
|
|
|
const ConditionalOperator *Exp = cast<ConditionalOperator>(this);
|
|
|
|
|
2007-07-16 03:26:56 +04:00
|
|
|
if (!Exp->getCond()->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated))
|
2007-07-11 21:01:13 +04:00
|
|
|
return false;
|
|
|
|
|
|
|
|
const Expr *TrueExp = Exp->getLHS();
|
|
|
|
const Expr *FalseExp = Exp->getRHS();
|
|
|
|
if (Result == 0) std::swap(TrueExp, FalseExp);
|
|
|
|
|
|
|
|
// Evaluate the false one first, discard the result.
|
2007-11-30 22:04:31 +03:00
|
|
|
if (FalseExp && !FalseExp->isIntegerConstantExpr(Result, Ctx, Loc, false))
|
2007-07-11 21:01:13 +04:00
|
|
|
return false;
|
|
|
|
// Evalute the true one, capture the result.
|
2007-11-30 22:04:31 +03:00
|
|
|
if (TrueExp &&
|
|
|
|
!TrueExp->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated))
|
2007-07-11 21:01:13 +04:00
|
|
|
return false;
|
|
|
|
break;
|
|
|
|
}
|
2008-04-08 08:40:51 +04:00
|
|
|
case CXXDefaultArgExprClass:
|
|
|
|
return cast<CXXDefaultArgExpr>(this)
|
|
|
|
->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Cases that are valid constant exprs fall through to here.
|
|
|
|
Result.setIsUnsigned(getType()->isUnsignedIntegerType());
|
|
|
|
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*.
|
2007-07-16 03:26:56 +04:00
|
|
|
bool Expr::isNullPointerConstant(ASTContext &Ctx) const {
|
2008-01-14 19:10:57 +03:00
|
|
|
// Strip off a cast to void*, if it exists.
|
|
|
|
if (const CastExpr *CE = dyn_cast<CastExpr>(this)) {
|
|
|
|
// Check that it is a cast to void*.
|
2008-02-13 20:29:58 +03:00
|
|
|
if (const PointerType *PT = CE->getType()->getAsPointerType()) {
|
2007-07-11 21:01:13 +04:00
|
|
|
QualType Pointee = PT->getPointeeType();
|
2008-02-20 23:55:12 +03:00
|
|
|
if (Pointee.getCVRQualifiers() == 0 &&
|
|
|
|
Pointee->isVoidType() && // to void*
|
2008-01-14 19:10:57 +03:00
|
|
|
CE->getSubExpr()->getType()->isIntegerType()) // from int.
|
|
|
|
return CE->getSubExpr()->isNullPointerConstant(Ctx);
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2008-01-14 19:10:57 +03:00
|
|
|
} 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);
|
2008-04-10 06:22:51 +04:00
|
|
|
} else if (const CXXDefaultArgExpr *DefaultArg
|
|
|
|
= dyn_cast<CXXDefaultArgExpr>(this)) {
|
2008-04-08 08:40:51 +04:00
|
|
|
// See through default argument expressions
|
|
|
|
return DefaultArg->getExpr()->isNullPointerConstant(Ctx);
|
2008-01-14 05:53:34 +03:00
|
|
|
}
|
2008-01-14 19:10:57 +03:00
|
|
|
|
|
|
|
// This expression must be an integer type.
|
|
|
|
if (!getType()->isIntegerType())
|
|
|
|
return false;
|
|
|
|
|
2007-07-11 21:01:13 +04:00
|
|
|
// If we have an integer constant expression, we need to *evaluate* it and
|
|
|
|
// test for the value 0.
|
|
|
|
llvm::APSInt Val(32);
|
2008-01-14 19:10:57 +03:00
|
|
|
return isIntegerConstantExpr(Val, Ctx, 0, true) && Val == 0;
|
2007-07-11 21:01:13 +04:00
|
|
|
}
|
2007-07-29 03:10:27 +04:00
|
|
|
|
2008-04-19 03:10:10 +04:00
|
|
|
unsigned ExtVectorElementExpr::getNumElements() const {
|
2007-08-03 20:00:20 +04:00
|
|
|
return strlen(Accessor.getName());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-03 01:47:28 +04:00
|
|
|
/// getComponentType - Determine whether the components of this access are
|
|
|
|
/// "point" "color" or "texture" elements.
|
2008-04-19 03:10:10 +04:00
|
|
|
ExtVectorElementExpr::ElementType
|
|
|
|
ExtVectorElementExpr::getElementType() const {
|
2007-07-29 03:10:27 +04:00
|
|
|
// derive the component type, no need to waste space.
|
|
|
|
const char *compStr = Accessor.getName();
|
2007-08-03 02:20:00 +04:00
|
|
|
|
2008-04-19 03:10:10 +04:00
|
|
|
if (ExtVectorType::getPointAccessorIdx(*compStr) != -1) return Point;
|
|
|
|
if (ExtVectorType::getColorAccessorIdx(*compStr) != -1) return Color;
|
2007-08-03 02:20:00 +04:00
|
|
|
|
2008-04-19 03:10:10 +04:00
|
|
|
assert(ExtVectorType::getTextureAccessorIdx(*compStr) != -1 &&
|
2007-08-03 02:20:00 +04:00
|
|
|
"getComponentType(): Illegal accessor");
|
|
|
|
return Texture;
|
2007-07-29 03:10:27 +04:00
|
|
|
}
|
2007-07-30 07:29:09 +04:00
|
|
|
|
2007-08-03 21:31:20 +04:00
|
|
|
/// containsDuplicateElements - Return true if any element access is
|
2007-08-03 01:47:28 +04:00
|
|
|
/// repeated.
|
2008-04-19 03:10:10 +04:00
|
|
|
bool ExtVectorElementExpr::containsDuplicateElements() const {
|
2007-07-30 07:29:09 +04:00
|
|
|
const char *compStr = Accessor.getName();
|
|
|
|
unsigned length = strlen(compStr);
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2007-08-03 03:36:59 +04:00
|
|
|
|
|
|
|
/// getEncodedElementAccess - We encode fields with two bits per component.
|
2008-04-19 03:10:10 +04:00
|
|
|
unsigned ExtVectorElementExpr::getEncodedElementAccess() const {
|
2007-08-03 03:36:59 +04:00
|
|
|
const char *compStr = Accessor.getName();
|
2007-08-03 21:31:20 +04:00
|
|
|
unsigned length = getNumElements();
|
2007-08-03 03:36:59 +04:00
|
|
|
|
|
|
|
unsigned Result = 0;
|
|
|
|
|
|
|
|
while (length--) {
|
|
|
|
Result <<= 2;
|
2008-04-19 03:10:10 +04:00
|
|
|
int Idx = ExtVectorType::getAccessorIdx(compStr[length]);
|
2007-08-03 03:36:59 +04:00
|
|
|
assert(Idx != -1 && "Invalid accessor letter");
|
|
|
|
Result |= Idx;
|
|
|
|
}
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42395 91177308-0d34-0410-b5e6-96231b3b80d8
2007-09-27 18:38:14 +04:00
|
|
|
// constructor for instance messages.
|
2007-09-29 02:22:11 +04:00
|
|
|
ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo,
|
2008-01-07 22:49:32 +03:00
|
|
|
QualType retType, ObjCMethodDecl *mproto,
|
2007-11-03 19:37:59 +03:00
|
|
|
SourceLocation LBrac, SourceLocation RBrac,
|
2007-11-15 16:05:42 +03:00
|
|
|
Expr **ArgExprs, unsigned nargs)
|
2007-11-03 19:37:59 +03:00
|
|
|
: Expr(ObjCMessageExprClass, retType), SelName(selInfo),
|
2008-05-01 21:26:20 +04:00
|
|
|
MethodProto(mproto) {
|
2007-11-15 16:05:42 +03:00
|
|
|
NumArgs = nargs;
|
|
|
|
SubExprs = new Expr*[NumArgs+1];
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42395 91177308-0d34-0410-b5e6-96231b3b80d8
2007-09-27 18:38:14 +04:00
|
|
|
SubExprs[RECEIVER] = receiver;
|
2007-11-15 16:05:42 +03:00
|
|
|
if (NumArgs) {
|
|
|
|
for (unsigned i = 0; i != NumArgs; ++i)
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42395 91177308-0d34-0410-b5e6-96231b3b80d8
2007-09-27 18:38:14 +04:00
|
|
|
SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
|
|
|
|
}
|
2007-09-19 03:55:05 +04:00
|
|
|
LBracloc = LBrac;
|
|
|
|
RBracloc = RBrac;
|
|
|
|
}
|
|
|
|
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42395 91177308-0d34-0410-b5e6-96231b3b80d8
2007-09-27 18:38:14 +04:00
|
|
|
// constructor for class messages.
|
|
|
|
// FIXME: clsName should be typed to ObjCInterfaceType
|
2007-09-29 02:22:11 +04:00
|
|
|
ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo,
|
2008-01-07 22:49:32 +03:00
|
|
|
QualType retType, ObjCMethodDecl *mproto,
|
2007-11-03 19:37:59 +03:00
|
|
|
SourceLocation LBrac, SourceLocation RBrac,
|
2007-11-15 16:05:42 +03:00
|
|
|
Expr **ArgExprs, unsigned nargs)
|
2007-11-03 19:37:59 +03:00
|
|
|
: Expr(ObjCMessageExprClass, retType), SelName(selInfo),
|
2008-05-01 21:26:20 +04:00
|
|
|
MethodProto(mproto) {
|
2007-11-15 16:05:42 +03:00
|
|
|
NumArgs = nargs;
|
|
|
|
SubExprs = new Expr*[NumArgs+1];
|
2008-05-01 21:26:20 +04:00
|
|
|
SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | 0x1);
|
2007-11-15 16:05:42 +03:00
|
|
|
if (NumArgs) {
|
|
|
|
for (unsigned i = 0; i != NumArgs; ++i)
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42395 91177308-0d34-0410-b5e6-96231b3b80d8
2007-09-27 18:38:14 +04:00
|
|
|
SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]);
|
|
|
|
}
|
2007-09-19 03:55:05 +04:00
|
|
|
LBracloc = LBrac;
|
|
|
|
RBracloc = RBrac;
|
|
|
|
}
|
|
|
|
|
2007-10-25 04:29:32 +04:00
|
|
|
bool ChooseExpr::isConditionTrue(ASTContext &C) const {
|
|
|
|
llvm::APSInt CondVal(32);
|
|
|
|
bool IsConst = getCond()->isIntegerConstantExpr(CondVal, C);
|
|
|
|
assert(IsConst && "Condition of choose expr must be i-c-e"); IsConst=IsConst;
|
|
|
|
return CondVal != 0;
|
|
|
|
}
|
|
|
|
|
2008-01-29 18:56:48 +03:00
|
|
|
static int64_t evaluateOffsetOf(ASTContext& C, const Expr *E)
|
|
|
|
{
|
|
|
|
if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) {
|
|
|
|
QualType Ty = ME->getBase()->getType();
|
|
|
|
|
|
|
|
RecordDecl *RD = Ty->getAsRecordType()->getDecl();
|
2008-03-05 21:54:05 +03:00
|
|
|
const ASTRecordLayout &RL = C.getASTRecordLayout(RD);
|
2008-01-29 18:56:48 +03:00
|
|
|
FieldDecl *FD = ME->getMemberDecl();
|
|
|
|
|
|
|
|
// FIXME: This is linear time.
|
|
|
|
unsigned i = 0, e = 0;
|
|
|
|
for (i = 0, e = RD->getNumMembers(); i != e; i++) {
|
|
|
|
if (RD->getMember(i) == FD)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return RL.getFieldOffset(i) + evaluateOffsetOf(C, ME->getBase());
|
|
|
|
} else if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) {
|
|
|
|
const Expr *Base = ASE->getBase();
|
|
|
|
llvm::APSInt Idx(32);
|
|
|
|
bool ICE = ASE->getIdx()->isIntegerConstantExpr(Idx, C);
|
|
|
|
assert(ICE && "Array index is not a constant integer!");
|
|
|
|
|
2008-03-05 21:54:05 +03:00
|
|
|
int64_t size = C.getTypeSize(ASE->getType());
|
2008-01-29 18:56:48 +03:00
|
|
|
size *= Idx.getSExtValue();
|
|
|
|
|
|
|
|
return size + evaluateOffsetOf(C, Base);
|
|
|
|
} else if (isa<CompoundLiteralExpr>(E))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
assert(0 && "Unknown offsetof subexpression!");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int64_t UnaryOperator::evaluateOffsetOf(ASTContext& C) const
|
|
|
|
{
|
|
|
|
assert(Opc == OffsetOf && "Unary operator not offsetof!");
|
|
|
|
|
2008-03-05 21:54:05 +03:00
|
|
|
unsigned CharSize = C.Target.getCharWidth();
|
2008-01-29 18:56:48 +03:00
|
|
|
return ::evaluateOffsetOf(C, Val) / CharSize;
|
|
|
|
}
|
|
|
|
|
2007-08-24 22:13:47 +04:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Child Iterators for iterating over subexpressions/substatements
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
// DeclRefExpr
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator DeclRefExpr::child_begin() { return child_iterator(); }
|
|
|
|
Stmt::child_iterator DeclRefExpr::child_end() { return child_iterator(); }
|
2007-08-24 22:13:47 +04:00
|
|
|
|
2007-11-12 17:29:37 +03:00
|
|
|
// ObjCIvarRefExpr
|
2008-05-02 22:40:22 +04:00
|
|
|
Stmt::child_iterator ObjCIvarRefExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&Base);
|
|
|
|
}
|
|
|
|
|
|
|
|
Stmt::child_iterator ObjCIvarRefExpr::child_end() {
|
|
|
|
return reinterpret_cast<Stmt**>(&Base)+1;
|
|
|
|
}
|
2007-11-12 17:29:37 +03:00
|
|
|
|
2007-08-24 22:13:47 +04:00
|
|
|
// PreDefinedExpr
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator PreDefinedExpr::child_begin() { return child_iterator(); }
|
|
|
|
Stmt::child_iterator PreDefinedExpr::child_end() { return child_iterator(); }
|
2007-08-24 22:13:47 +04:00
|
|
|
|
|
|
|
// IntegerLiteral
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator IntegerLiteral::child_begin() { return child_iterator(); }
|
|
|
|
Stmt::child_iterator IntegerLiteral::child_end() { return child_iterator(); }
|
2007-08-24 22:13:47 +04:00
|
|
|
|
|
|
|
// CharacterLiteral
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator CharacterLiteral::child_begin() { return child_iterator(); }
|
|
|
|
Stmt::child_iterator CharacterLiteral::child_end() { return child_iterator(); }
|
2007-08-24 22:13:47 +04:00
|
|
|
|
|
|
|
// FloatingLiteral
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator FloatingLiteral::child_begin() { return child_iterator(); }
|
|
|
|
Stmt::child_iterator FloatingLiteral::child_end() { return child_iterator(); }
|
2007-08-24 22:13:47 +04:00
|
|
|
|
2007-08-26 07:42:43 +04:00
|
|
|
// ImaginaryLiteral
|
|
|
|
Stmt::child_iterator ImaginaryLiteral::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&Val);
|
|
|
|
}
|
|
|
|
Stmt::child_iterator ImaginaryLiteral::child_end() {
|
|
|
|
return reinterpret_cast<Stmt**>(&Val)+1;
|
|
|
|
}
|
|
|
|
|
2007-08-24 22:13:47 +04:00
|
|
|
// StringLiteral
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator StringLiteral::child_begin() { return child_iterator(); }
|
|
|
|
Stmt::child_iterator StringLiteral::child_end() { return child_iterator(); }
|
2007-08-24 22:13:47 +04:00
|
|
|
|
|
|
|
// ParenExpr
|
|
|
|
Stmt::child_iterator ParenExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&Val);
|
|
|
|
}
|
|
|
|
Stmt::child_iterator ParenExpr::child_end() {
|
2007-08-26 07:42:43 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&Val)+1;
|
2007-08-24 22:13:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// UnaryOperator
|
|
|
|
Stmt::child_iterator UnaryOperator::child_begin() {
|
2007-12-15 03:39:18 +03:00
|
|
|
return reinterpret_cast<Stmt**>(&Val);
|
2007-08-24 22:13:47 +04:00
|
|
|
}
|
|
|
|
Stmt::child_iterator UnaryOperator::child_end() {
|
2007-12-15 03:39:18 +03:00
|
|
|
return reinterpret_cast<Stmt**>(&Val+1);
|
2007-08-24 22:13:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// SizeOfAlignOfTypeExpr
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator SizeOfAlignOfTypeExpr::child_begin() {
|
2007-12-15 01:52:23 +03:00
|
|
|
// If the type is a VLA type (and not a typedef), the size expression of the
|
|
|
|
// VLA needs to be treated as an executable expression.
|
|
|
|
if (VariableArrayType* T = dyn_cast<VariableArrayType>(Ty.getTypePtr()))
|
|
|
|
return child_iterator(T);
|
|
|
|
else
|
|
|
|
return child_iterator();
|
2007-10-19 03:28:49 +04:00
|
|
|
}
|
|
|
|
Stmt::child_iterator SizeOfAlignOfTypeExpr::child_end() {
|
2007-12-15 01:52:23 +03:00
|
|
|
return child_iterator();
|
2007-10-19 03:28:49 +04:00
|
|
|
}
|
2007-08-24 22:13:47 +04:00
|
|
|
|
|
|
|
// ArraySubscriptExpr
|
2007-08-25 00:06:47 +04:00
|
|
|
Stmt::child_iterator ArraySubscriptExpr::child_begin() {
|
2007-08-24 22:13:47 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs);
|
|
|
|
}
|
2007-08-25 00:06:47 +04:00
|
|
|
Stmt::child_iterator ArraySubscriptExpr::child_end() {
|
2007-08-26 07:42:43 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR;
|
2007-08-24 22:13:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// CallExpr
|
2007-08-25 00:06:47 +04:00
|
|
|
Stmt::child_iterator CallExpr::child_begin() {
|
2007-08-28 01:11:44 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs[0]);
|
2007-08-24 22:13:47 +04:00
|
|
|
}
|
2007-08-25 00:06:47 +04:00
|
|
|
Stmt::child_iterator CallExpr::child_end() {
|
2007-08-28 01:11:44 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs[NumArgs+ARGS_START]);
|
2007-08-24 22:13:47 +04:00
|
|
|
}
|
2007-08-25 00:06:47 +04:00
|
|
|
|
|
|
|
// MemberExpr
|
|
|
|
Stmt::child_iterator MemberExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&Base);
|
|
|
|
}
|
|
|
|
Stmt::child_iterator MemberExpr::child_end() {
|
2007-08-26 07:42:43 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&Base)+1;
|
2007-08-25 00:06:47 +04:00
|
|
|
}
|
|
|
|
|
2008-04-19 03:10:10 +04:00
|
|
|
// ExtVectorElementExpr
|
|
|
|
Stmt::child_iterator ExtVectorElementExpr::child_begin() {
|
2007-08-25 00:06:47 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&Base);
|
|
|
|
}
|
2008-04-19 03:10:10 +04:00
|
|
|
Stmt::child_iterator ExtVectorElementExpr::child_end() {
|
2007-08-26 07:42:43 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&Base)+1;
|
2007-08-25 00:06:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// CompoundLiteralExpr
|
|
|
|
Stmt::child_iterator CompoundLiteralExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&Init);
|
|
|
|
}
|
|
|
|
Stmt::child_iterator CompoundLiteralExpr::child_end() {
|
2007-08-26 07:42:43 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&Init)+1;
|
2007-08-25 00:06:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// ImplicitCastExpr
|
|
|
|
Stmt::child_iterator ImplicitCastExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&Op);
|
|
|
|
}
|
|
|
|
Stmt::child_iterator ImplicitCastExpr::child_end() {
|
2007-08-26 07:42:43 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&Op)+1;
|
2007-08-25 00:06:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// CastExpr
|
|
|
|
Stmt::child_iterator CastExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&Op);
|
|
|
|
}
|
|
|
|
Stmt::child_iterator CastExpr::child_end() {
|
2007-08-26 07:42:43 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&Op)+1;
|
2007-08-25 00:06:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// BinaryOperator
|
|
|
|
Stmt::child_iterator BinaryOperator::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs);
|
|
|
|
}
|
|
|
|
Stmt::child_iterator BinaryOperator::child_end() {
|
2007-08-26 07:42:43 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR;
|
2007-08-25 00:06:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// ConditionalOperator
|
|
|
|
Stmt::child_iterator ConditionalOperator::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs);
|
|
|
|
}
|
|
|
|
Stmt::child_iterator ConditionalOperator::child_end() {
|
2007-08-26 07:42:43 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR;
|
2007-08-25 00:06:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// AddrLabelExpr
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator AddrLabelExpr::child_begin() { return child_iterator(); }
|
|
|
|
Stmt::child_iterator AddrLabelExpr::child_end() { return child_iterator(); }
|
2007-08-25 00:06:47 +04:00
|
|
|
|
|
|
|
// StmtExpr
|
|
|
|
Stmt::child_iterator StmtExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&SubStmt);
|
|
|
|
}
|
|
|
|
Stmt::child_iterator StmtExpr::child_end() {
|
2007-08-26 07:42:43 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&SubStmt)+1;
|
2007-08-25 00:06:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// TypesCompatibleExpr
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator TypesCompatibleExpr::child_begin() {
|
|
|
|
return child_iterator();
|
|
|
|
}
|
|
|
|
|
|
|
|
Stmt::child_iterator TypesCompatibleExpr::child_end() {
|
|
|
|
return child_iterator();
|
|
|
|
}
|
2007-08-25 00:06:47 +04:00
|
|
|
|
|
|
|
// ChooseExpr
|
|
|
|
Stmt::child_iterator ChooseExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs);
|
|
|
|
}
|
|
|
|
|
|
|
|
Stmt::child_iterator ChooseExpr::child_end() {
|
2007-08-26 07:42:43 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR;
|
2007-08-25 00:06:47 +04:00
|
|
|
}
|
|
|
|
|
2008-01-17 20:46:27 +03:00
|
|
|
// OverloadExpr
|
|
|
|
Stmt::child_iterator OverloadExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs[0]);
|
|
|
|
}
|
|
|
|
Stmt::child_iterator OverloadExpr::child_end() {
|
2008-01-30 23:50:20 +03:00
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs[NumExprs]);
|
2008-01-17 20:46:27 +03:00
|
|
|
}
|
|
|
|
|
2007-10-16 00:28:48 +04:00
|
|
|
// VAArgExpr
|
|
|
|
Stmt::child_iterator VAArgExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&Val);
|
|
|
|
}
|
|
|
|
|
|
|
|
Stmt::child_iterator VAArgExpr::child_end() {
|
|
|
|
return reinterpret_cast<Stmt**>(&Val)+1;
|
|
|
|
}
|
|
|
|
|
2007-08-31 08:56:16 +04:00
|
|
|
// InitListExpr
|
|
|
|
Stmt::child_iterator InitListExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&InitExprs[0]);
|
|
|
|
}
|
|
|
|
Stmt::child_iterator InitListExpr::child_end() {
|
2008-05-07 20:50:14 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&InitExprs[getNumInits()-1]);
|
2007-08-31 08:56:16 +04:00
|
|
|
}
|
|
|
|
|
2007-08-25 00:06:47 +04:00
|
|
|
// ObjCStringLiteral
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator ObjCStringLiteral::child_begin() {
|
|
|
|
return child_iterator();
|
|
|
|
}
|
|
|
|
Stmt::child_iterator ObjCStringLiteral::child_end() {
|
|
|
|
return child_iterator();
|
|
|
|
}
|
2007-08-25 00:06:47 +04:00
|
|
|
|
|
|
|
// ObjCEncodeExpr
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator ObjCEncodeExpr::child_begin() { return child_iterator(); }
|
|
|
|
Stmt::child_iterator ObjCEncodeExpr::child_end() { return child_iterator(); }
|
2007-08-25 00:06:47 +04:00
|
|
|
|
2007-10-17 00:40:23 +04:00
|
|
|
// ObjCSelectorExpr
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator ObjCSelectorExpr::child_begin() {
|
|
|
|
return child_iterator();
|
|
|
|
}
|
|
|
|
Stmt::child_iterator ObjCSelectorExpr::child_end() {
|
|
|
|
return child_iterator();
|
|
|
|
}
|
2007-10-17 00:40:23 +04:00
|
|
|
|
2007-10-17 20:58:11 +04:00
|
|
|
// ObjCProtocolExpr
|
2007-10-19 03:28:49 +04:00
|
|
|
Stmt::child_iterator ObjCProtocolExpr::child_begin() {
|
|
|
|
return child_iterator();
|
|
|
|
}
|
|
|
|
Stmt::child_iterator ObjCProtocolExpr::child_end() {
|
|
|
|
return child_iterator();
|
|
|
|
}
|
2007-10-17 20:58:11 +04:00
|
|
|
|
2007-09-19 03:55:05 +04:00
|
|
|
// ObjCMessageExpr
|
2008-05-01 21:26:20 +04:00
|
|
|
Stmt::child_iterator ObjCMessageExpr::child_begin() {
|
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs[ getReceiver() ? 0 : ARGS_START ]);
|
2007-09-19 03:55:05 +04:00
|
|
|
}
|
|
|
|
Stmt::child_iterator ObjCMessageExpr::child_end() {
|
Add SelectorInfo (similar in spirit to IdentifierInfo). The key difference is SelectorInfo is not string-oriented, it is a unique aggregate of IdentifierInfo's (using a folding set). SelectorInfo also has a richer API that simplifies the parser/action interface. 3 noteworthy benefits:
#1: It is cleaner. I never "liked" storing keyword selectors (i.e. foo:bar:baz) in the IdentifierTable.
#2: It is more space efficient. Since Cocoa keyword selectors can be quite long, this technique is space saving. For Cocoa.h, pulling the keyword selectors out saves ~180k. The cost of the SelectorInfo data is ~100k. Saves ~80k, or 43%.
#3: It results in many API simplifications. Here are some highlights:
- Removed 3 actions (ActOnKeywordMessage, ActOnUnaryMessage, & one flavor of ObjcBuildMethodDeclaration that was specific to unary messages).
- Removed 3 funky structs from DeclSpec.h (ObjcKeywordMessage, ObjcKeywordDecl, and ObjcKeywordInfo).
- Removed 2 ivars and 2 constructors from ObjCMessageExpr (fyi, this space savings has not been measured).
I am happy with the way it turned out (though it took a bit more hacking than I expected). Given the central role of selectors in ObjC, making sure this is "right" will pay dividends later.
Thanks to Chris for talking this through with me and suggesting this approach.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@42395 91177308-0d34-0410-b5e6-96231b3b80d8
2007-09-27 18:38:14 +04:00
|
|
|
return reinterpret_cast<Stmt**>(&SubExprs[getNumArgs()+ARGS_START]);
|
2007-09-19 03:55:05 +04:00
|
|
|
}
|
|
|
|
|