Newer
Older
//===--- 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/APValue.h"
Chris Lattner
committed
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/TargetInfo.h"
#include <algorithm>
using namespace clang;
//===----------------------------------------------------------------------===//
// Primary Expressions.
//===----------------------------------------------------------------------===//
Sebastian Redl
committed
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);
}
Sebastian Redl
committed
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);
}
Douglas Gregor
committed
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());
}
Sebastian Redl
committed
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);
Steve Naroff
committed
// 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;
Chris Lattner
committed
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);
}
Ted Kremenek
committed
void StringLiteral::Destroy(ASTContext &C) {
Ted Kremenek
committed
this->~StringLiteral();
C.Deallocate(this);
Chris Lattner
committed
}
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.
//===----------------------------------------------------------------------===//
Ted Kremenek
committed
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) {
Ted Kremenek
committed
SubExprs = new (C) Stmt*[numargs+1];
SubExprs[FN] = fn;
for (unsigned i = 0; i != numargs; ++i)
SubExprs[i+ARGS_START] = args[i];
Ted Kremenek
committed
RParenLoc = rparenloc;
}
Ted Kremenek
committed
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) {
Ted Kremenek
committed
SubExprs = new (C) Stmt*[numargs+1];
SubExprs[FN] = fn;
for (unsigned i = 0; i != numargs; ++i)
SubExprs[i+ARGS_START] = args[i];
Ted Kremenek
committed
RParenLoc = rparenloc;
CallExpr::CallExpr(ASTContext &C, EmptyShell Empty)
: Expr(CallExprClass, Empty), SubExprs(0), NumArgs(0) {
SubExprs = new (C) Stmt*[1];
}
Ted Kremenek
committed
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)
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;
SubExprs = NewSubExprs;
this->NumArgs = NumArgs;
}
Chris Lattner
committed
/// 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)()).
Chris Lattner
committed
return 0;
const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
if (!DRE)
Chris Lattner
committed
return 0;
const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl());
if (!FDecl)
Chris Lattner
committed
return 0;
Douglas Gregor
committed
if (!FDecl->getIdentifier())
return 0;
return FDecl->getBuiltinID(Context);
Chris Lattner
committed
}
Anders Carlsson
committed
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();
}
Chris Lattner
committed
/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
/// corresponds to, e.g. "<<=".
const char *BinaryOperator::getOpcodeStr(Opcode Op) {
switch (Op) {
Douglas Gregor
committed
case PtrMemD: return ".*";
case PtrMemI: return "->*";
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
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 ",";
}
Douglas Gregor
committed
return "";
BinaryOperator::Opcode
BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) {
switch (OO) {
default: assert(false && "Not an overloadable binary operator");
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
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),
Douglas Gregor
committed
UnionFieldInit(0), HadArrayRangeDesignator(false) {
InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits);
Chris Lattner
committed
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();
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();
}
Chris Lattner
committed
//===----------------------------------------------------------------------===//
// 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;
Chris Lattner
committed
switch (getStmtClass()) {
default:
Loc = getExprLoc();
R1 = getSourceRange();
return true;
Chris Lattner
committed
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()->
isUnusedResultAWarning(Loc, R1, R2);
Chris Lattner
committed
case UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(this);
switch (UO->getOpcode()) {
Chris Lattner
committed
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;
Chris Lattner
committed
case UnaryOperator::Extension:
return UO->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2);
Chris Lattner
committed
}
Loc = UO->getOperatorLoc();
R1 = UO->getSubExpr()->getSourceRange();
return true;
Chris Lattner
committed
}
Chris Lattner
committed
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);
Chris Lattner
committed
if (BO->isAssignmentOp())
return false;
Loc = BO->getOperatorLoc();
R1 = BO->getLHS()->getSourceRange();
R2 = BO->getRHS()->getSourceRange();
return true;
Chris Lattner
committed
}
Chris Lattner
committed
case CompoundAssignOperatorClass:
Chris Lattner
committed
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);
// 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;
Chris Lattner
committed
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;
Chris Lattner
committed
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:
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;
// 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:
Chris Lattner
committed
// 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:
case CXXExprWithTemporariesClass:
return cast<CXXExprWithTemporaries>(this)
->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2);
Chris Lattner
committed
}
/// 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
Chris Lattner
committed
/// - (__real__ e) and (__imag__ e) where e is an lvalue [GNU extension]
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())
// Allow qualified void which is an incomplete type other than void (yuck).
if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers())
return LV_Valid;
}
// Check whether the expression can be sanely treated like an l-value
Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const {
case StringLiteralClass: // C99 6.5.1p4
case ObjCEncodeExprClass: // @encode behaves like its string in every way.
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);
case DeclRefExprClass:
case QualifiedDeclRefExprClass: { // C99 6.5.1p2
const NamedDecl *RefdDecl = cast<DeclRefExpr>(this)->getDecl();
if (DeclCanBeLvalue(RefdDecl, Ctx))
Chris Lattner
committed
}
Steve Naroff
committed
case BlockDeclRefExprClass: {
const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this);
Steve Naroff
committed
if (isa<VarDecl>(BDR->getDecl()))
Steve Naroff
committed
return LV_Valid;
break;
}
case MemberExprClass: {
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);
Chris Lattner
committed
case UnaryOperatorClass:
if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref)
Chris Lattner
committed
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;
case ImplicitCastExprClass:
return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid
: LV_InvalidExpression;
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.
Anders Carlsson
committed
QualType ReturnType = cast<CallExpr>(this)->getCallReturnType();
if (ReturnType->isLValueReferenceType())
return LV_Valid;
break;
}
case ChooseExprClass:
// __builtin_choose_expr is an lvalue if the selected operand is.
return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)->isLvalue(Ctx);
Nate Begeman
committed
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;
Fariborz Jahanian
committed
case ObjCKVCRefExprClass: // FIXME: check if read-only property.
return LV_Valid;
Douglas Gregor
committed
return LV_Valid;
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx);
case CXXConditionDeclExprClass:
return LV_Valid;
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;
}
/// 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);
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;
Chris Lattner
committed
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; }); }
//
const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this);
if (!BDR->isByRef() && isa<VarDecl>(BDR->getDecl()))
return MLV_NotBlockQualified;
}
QualType CT = Ctx.getCanonicalType(getType());
if (CT.isConstQualified())
// Assigning to an 'implicit' property?
const ObjCKVCRefExpr* KVCExpr = cast<ObjCKVCRefExpr>(this);
if (KVCExpr->getSetterMethod() == 0)
return MLV_NoSetterProperty;
}
/// hasGlobalStorage - Return true if this expression has static storage
Chris Lattner
committed
/// 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;
Chris Lattner
committed
case ParenExprClass:
return cast<ParenExpr>(this)->getSubExpr()->hasGlobalStorage();
Chris Lattner
committed
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;
}
const MemberExpr *M = cast<MemberExpr>(this);
return !M->isArrow() && M->getBase()->hasGlobalStorage();
Chris Lattner
committed
case ArraySubscriptExprClass:
return cast<ArraySubscriptExpr>(this)->getBase()->hasGlobalStorage();
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);