struct CallStackFrame;
struct EvalInfo;
+ QualType getType(APValue::LValueBase B) {
+ if (!B) return QualType();
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>())
+ return D->getType();
+ return B.get<const Expr*>()->getType();
+ }
+
/// Get an LValue path entry, which is known to not be an array index, as a
/// field declaration.
const FieldDecl *getAsField(APValue::LValuePathEntry E) {
ArrayRef<PathEntry> VEntries = V.getLValuePath();
Entries.insert(Entries.end(), VEntries.begin(), VEntries.end());
if (V.getLValueBase())
- ArrayElement = SubobjectIsArrayElement(V.getLValueBase()->getType(),
+ ArrayElement = SubobjectIsArrayElement(getType(V.getLValueBase()),
V.getLValuePath());
else
assert(V.getLValuePath().empty() &&"Null pointer with nonempty path");
CCValue(const APSInt &R, const APSInt &I) : APValue(R, I) {}
CCValue(const APFloat &R, const APFloat &I) : APValue(R, I) {}
CCValue(const CCValue &V) : APValue(V), CallFrame(V.CallFrame) {}
- CCValue(const Expr *B, const CharUnits &O, CallStackFrame *F,
+ CCValue(LValueBase B, const CharUnits &O, CallStackFrame *F,
const SubobjectDesignator &D) :
APValue(B, O, APValue::NoLValuePath()), CallFrame(F), Designator(D) {}
CCValue(const APValue &V, GlobalValue) :
};
struct LValue {
- const Expr *Base;
+ APValue::LValueBase Base;
CharUnits Offset;
CallStackFrame *Frame;
SubobjectDesignator Designator;
- const Expr *getLValueBase() const { return Base; }
+ const APValue::LValueBase getLValueBase() const { return Base; }
CharUnits &getLValueOffset() { return Offset; }
const CharUnits &getLValueOffset() const { return Offset; }
CallStackFrame *getLValueFrame() const { return Frame; }
Designator = V.getLValueDesignator();
}
- void setExpr(const Expr *E, CallStackFrame *F = 0) {
- Base = E;
+ void set(APValue::LValueBase B, CallStackFrame *F = 0) {
+ Base = B;
Offset = CharUnits::Zero();
Frame = F;
Designator = SubobjectDesignator();
Builtin == Builtin::BI__builtin___NSStringMakeConstantString);
}
-static bool IsGlobalLValue(const Expr* E) {
+static bool IsGlobalLValue(APValue::LValueBase B) {
// C++11 [expr.const]p3 An address constant expression is a prvalue core
// constant expression of pointer type that evaluates to...
// ... a null pointer value, or a prvalue core constant expression of type
// std::nullptr_t.
- if (!E) return true;
+ if (!B) return true;
- switch (E->getStmtClass()) {
- default:
- return false;
- case Expr::DeclRefExprClass: {
- const DeclRefExpr *DRE = cast<DeclRefExpr>(E);
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
// ... the address of an object with static storage duration,
- if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->hasGlobalStorage();
- // ... to the address of a function,
- if (isa<FunctionDecl>(DRE->getDecl()))
- return true;
- return false;
+ // ... the address of a function,
+ return isa<FunctionDecl>(D);
}
+
+ const Expr *E = B.get<const Expr*>();
+ switch (E->getStmtClass()) {
+ default:
+ return false;
case Expr::CompoundLiteralExprClass:
return cast<CompoundLiteralExpr>(E)->isFileScope();
// A string literal has static storage duration.
}
const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
- if (!LVal.Base)
- return 0;
-
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(LVal.Base))
- return DRE->getDecl();
-
- // FIXME: Static data members accessed via a MemberExpr are represented as
- // that MemberExpr. We should use the Decl directly instead.
- if (const MemberExpr *ME = dyn_cast<MemberExpr>(LVal.Base)) {
- assert(!isa<FieldDecl>(ME->getMemberDecl()) && "shouldn't see fields here");
- return ME->getMemberDecl();
- }
-
- return 0;
+ return LVal.Base.dyn_cast<const ValueDecl*>();
}
static bool IsLiteralLValue(const LValue &Value) {
- return Value.Base &&
- !isa<DeclRefExpr>(Value.Base) &&
- !isa<MemberExpr>(Value.Base) &&
- !isa<MaterializeTemporaryExpr>(Value.Base);
+ return Value.Base.dyn_cast<const Expr*>() && !Value.Frame;
}
static bool IsWeakDecl(const ValueDecl *Decl) {
}
static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) {
- const Expr* Base = Value.Base;
-
// A null base expression indicates a null pointer. These are always
// evaluatable, and they are false unless the offset is zero.
- if (!Base) {
+ if (!Value.Base) {
Result = !Value.Offset.isZero();
return true;
}
// Require the base expression to be a global l-value.
// FIXME: C++11 requires such conversions. Remove this check.
- if (!IsGlobalLValue(Base)) return false;
+ if (!IsGlobalLValue(Value.Base)) return false;
// We have a non-null base expression. These are generally known to
// be true, but if it'a decl-ref to a weak symbol it can be null at
if (D.Invalid || !Result.Base)
return false;
- const Type *T = Result.Base->getType().getTypePtr();
+ const Type *T = getType(Result.Base).getTypePtr();
// Find path prefix which leads to the most-derived subobject.
unsigned MostDerivedPathLength = 0;
}
/// Try to evaluate the initializer for a variable declaration.
-static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E,const VarDecl *VD,
+static bool EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD,
CallStackFrame *Frame, CCValue &Result) {
// If this is a parameter to an active constexpr function call, perform
// argument substitution.
APValue EvalResult;
InitInfo.setEvaluatingDecl(VD, EvalResult);
LValue LVal;
- LVal.setExpr(E);
+ LVal.set(VD);
// FIXME: The caller will need to know whether the value was a constant
// expression. If not, we should propagate up a diagnostic.
if (!EvaluateConstantExpression(EvalResult, InitInfo, LVal, Init)) {
/// \param RVal - The produced value will be placed here.
static bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
const LValue &LVal, CCValue &RVal) {
- const Expr *Base = LVal.Base;
+ const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
CallStackFrame *Frame = LVal.Frame;
// FIXME: Indirection through a null pointer deserves a diagnostic.
- if (!Base)
+ if (!LVal.Base)
return false;
- if (const ValueDecl *D = GetLValueBaseDecl(LVal)) {
+ if (const ValueDecl *D = LVal.Base.dyn_cast<const ValueDecl*>()) {
// In C++98, const, non-volatile integers initialized with ICEs are ICEs.
// In C++11, constexpr, non-volatile variables initialized with constant
// expressions are constant expressions too. Inside constexpr functions,
// objects in constant expressions), but lvalue-to-rvalue conversions on
// them are not permitted.
const VarDecl *VD = dyn_cast<VarDecl>(D);
- QualType VT = VD->getType();
if (!VD || VD->isInvalidDecl())
return false;
+ QualType VT = VD->getType();
if (!isa<ParmVarDecl>(VD)) {
if (!IsConstNonVolatile(VT))
return false;
!VD->isConstexpr())
return false;
}
- if (!EvaluateVarDeclInit(Info, LVal.Base, VD, Frame, RVal))
+ if (!EvaluateVarDeclInit(Info, VD, Frame, RVal))
return false;
if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue())
// value we were originally given.
assert(RVal.getLValueOffset().isZero() &&
"offset for lvalue init of non-reference");
- Base = RVal.getLValueBase();
+ Base = RVal.getLValueBase().get<const Expr*>();
Frame = RVal.getLValueFrame();
}
return EvaluateLValue(Object, This, Info);
// Implicitly promote a prvalue *this object to a glvalue.
- This.setExpr(Object, Info.CurrentCall);
+ This.set(Object, Info.CurrentCall);
return EvaluateConstantExpression(Info.CurrentCall->Temporaries[Object], Info,
This, Object);
}
} else if (CalleeType->isFunctionPointerType()) {
CCValue Call;
if (!Evaluate(Call, Info, Callee) || !Call.isLValue() ||
- !Call.getLValueBase() || !Call.getLValueOffset().isZero())
+ !Call.getLValueOffset().isZero())
return DerivedError(Callee);
- const Expr *Base = Call.getLValueBase();
-
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base))
- FD = dyn_cast<FunctionDecl>(DRE->getDecl());
- else if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base))
- FD = dyn_cast<FunctionDecl>(ME->getMemberDecl());
+ FD = dyn_cast_or_null<FunctionDecl>(
+ Call.getLValueBase().dyn_cast<const ValueDecl*>());
if (!FD)
return DerivedError(Callee);
//
// LValue evaluation produces values comprising a base expression of one of the
// following types:
-// * DeclRefExpr
-// * MemberExpr for a static member
+// - Declarations
+// * VarDecl
+// * FunctionDecl
+// - Literals
// * CompoundLiteralExpr in C
// * StringLiteral
// * PredefinedExpr
// * AddrLabelExpr
// * BlockExpr
// * CallExpr for a MakeStringConstant builtin
-// plus an offset in bytes. It can also produce lvalues referring to locals. In
-// that case, the Frame will point to a stack frame, and the Expr is used as a
-// key to find the relevant temporary's value.
+// - Locals and temporaries
+// * Any Expr, with a Frame indicating the function in which the temporary was
+// evaluated.
+// plus an offset in bytes.
//===----------------------------------------------------------------------===//
namespace {
class LValueExprEvaluator
LValue &Result;
const Decl *PrevDecl;
- bool Success(const Expr *E) {
- Result.setExpr(E);
+ bool Success(APValue::LValueBase B) {
+ Result.set(B);
return true;
}
public:
}
bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
- if (isa<FunctionDecl>(E->getDecl()))
- return Success(E);
- if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl()))
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(E->getDecl()))
+ return Success(FD);
+ if (const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl()))
return VisitVarDecl(E, VD);
return Error(E);
}
bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
if (!VD->getType()->isReferenceType()) {
if (isa<ParmVarDecl>(VD)) {
- Result.setExpr(E, Info.CurrentCall);
+ Result.set(VD, Info.CurrentCall);
return true;
}
- return Success(E);
+ return Success(VD);
}
CCValue V;
- if (EvaluateVarDeclInit(Info, E, VD, Info.CurrentCall, V))
+ if (EvaluateVarDeclInit(Info, VD, Info.CurrentCall, V))
return Success(V, E);
return Error(E);
bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {
- Result.setExpr(E, Info.CurrentCall);
+ Result.set(E, Info.CurrentCall);
return EvaluateConstantExpression(Info.CurrentCall->Temporaries[E], Info,
Result, E->GetTemporaryExpr());
}
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(E->getMemberDecl())) {
if (MD->isStatic()) {
VisitIgnoredValue(E->getBase());
- return Success(E);
+ return Success(MD);
}
}
LValue &Result;
bool Success(const Expr *E) {
- Result.setExpr(E);
+ Result.set(E);
return true;
}
public:
if (Value.isInt()) {
unsigned Size = Info.Ctx.getTypeSize(E->getType());
uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue();
- Result.Base = 0;
+ Result.Base = (Expr*)0;
Result.Offset = CharUnits::fromQuantity(N);
Result.Frame = 0;
Result.Designator.setInvalid();
private:
CharUnits GetAlignOfExpr(const Expr *E);
CharUnits GetAlignOfType(QualType T);
- static QualType GetObjectType(const Expr *E);
+ static QualType GetObjectType(APValue::LValueBase B);
bool TryEvaluateBuiltinObjectSize(const CallExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
};
/// Retrieves the "underlying object type" of the given expression,
/// as used by __builtin_object_size.
-QualType IntExprEvaluator::GetObjectType(const Expr *E) {
- if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl()))
+QualType IntExprEvaluator::GetObjectType(APValue::LValueBase B) {
+ if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) {
+ if (const VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->getType();
- } else if (isa<CompoundLiteralExpr>(E)) {
- return E->getType();
+ } else if (const Expr *E = B.get<const Expr*>()) {
+ if (isa<CompoundLiteralExpr>(E))
+ return E->getType();
}
return QualType();
return false;
// If we can prove the base is null, lower to zero now.
- const Expr *LVBase = Base.getLValueBase();
- if (!LVBase) return Success(0, E);
+ if (!Base.getLValueBase()) return Success(0, E);
- QualType T = GetObjectType(LVBase);
+ QualType T = GetObjectType(Base.getLValueBase());
if (T.isNull() ||
T->isIncompleteType() ||
T->isFunctionType() ||
if (!B.getLValueBase())
return false;
- if (A.getLValueBase() != B.getLValueBase()) {
+ if (A.getLValueBase().getOpaqueValue() !=
+ B.getLValueBase().getOpaqueValue()) {
const Decl *ADecl = GetLValueBaseDecl(A);
if (!ADecl)
return false;
return false;
} else if (E->getType()->isArrayType() && E->getType()->isLiteralType()) {
LValue LV;
- LV.setExpr(E, Info.CurrentCall);
+ LV.set(E, Info.CurrentCall);
if (!EvaluateArray(E, LV, Info.CurrentCall->Temporaries[E], Info))
return false;
Result = Info.CurrentCall->Temporaries[E];
} else if (E->getType()->isRecordType() && E->getType()->isLiteralType()) {
LValue LV;
- LV.setExpr(E, Info.CurrentCall);
+ LV.set(E, Info.CurrentCall);
if (!EvaluateRecord(E, LV, Info.CurrentCall->Temporaries[E], Info))
return false;
Result = Info.CurrentCall->Temporaries[E];