MemberPointer,
AddrLabelDiff
};
- typedef llvm::PointerUnion<const ValueDecl *, const Expr *> LValueBase;
+
+ class LValueBase {
+ public:
+ typedef llvm::PointerUnion<const ValueDecl *, const Expr *> PtrTy;
+
+ LValueBase() : CallIndex(0), Version(0) {}
+
+ template <class T>
+ LValueBase(T P, unsigned I = 0, unsigned V = 0)
+ : Ptr(P), CallIndex(I), Version(V) {}
+
+ template <class T>
+ bool is() const { return Ptr.is<T>(); }
+
+ template <class T>
+ T get() const { return Ptr.get<T>(); }
+
+ template <class T>
+ T dyn_cast() const { return Ptr.dyn_cast<T>(); }
+
+ void *getOpaqueValue() const;
+
+ bool isNull() const;
+
+ explicit operator bool () const;
+
+ PtrTy getPointer() const {
+ return Ptr;
+ }
+
+ unsigned getCallIndex() const {
+ return CallIndex;
+ }
+
+ void setCallIndex(unsigned Index) {
+ CallIndex = Index;
+ }
+
+ unsigned getVersion() const {
+ return Version;
+ }
+
+ bool operator==(const LValueBase &Other) const {
+ return Ptr == Other.Ptr && CallIndex == Other.CallIndex &&
+ Version == Other.Version;
+ }
+
+ private:
+ PtrTy Ptr;
+ unsigned CallIndex, Version;
+ };
+
typedef llvm::PointerIntPair<const Decl *, 1, bool> BaseOrMemberType;
union LValuePathEntry {
/// BaseOrMember - The FieldDecl or CXXRecordDecl indicating the next item
}
APValue(const APValue &RHS);
APValue(APValue &&RHS) : Kind(Uninitialized) { swap(RHS); }
- APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex,
+ APValue(LValueBase B, const CharUnits &O, NoLValuePath N,
bool IsNullPtr = false)
: Kind(Uninitialized) {
- MakeLValue(); setLValue(B, O, N, CallIndex, IsNullPtr);
+ MakeLValue(); setLValue(B, O, N, IsNullPtr);
}
APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path,
- bool OnePastTheEnd, unsigned CallIndex, bool IsNullPtr = false)
+ bool OnePastTheEnd, bool IsNullPtr = false)
: Kind(Uninitialized) {
- MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex, IsNullPtr);
+ MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, IsNullPtr);
}
APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
MakeArray(InitElts, Size);
bool hasLValuePath() const;
ArrayRef<LValuePathEntry> getLValuePath() const;
unsigned getLValueCallIndex() const;
+ unsigned getLValueVersion() const;
bool isNullPointer() const;
APValue &getVectorElt(unsigned I) {
((ComplexAPFloat *)(char *)Data.buffer)->Imag = std::move(I);
}
void setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
- unsigned CallIndex, bool IsNullPtr);
+ bool IsNullPtr);
void setLValue(LValueBase B, const CharUnits &O,
ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd,
- unsigned CallIndex, bool IsNullPtr);
+ bool IsNullPtr);
void setUnion(const FieldDecl *Field, const APValue &Value) {
assert(isUnion() && "Invalid accessor");
((UnionData*)(char*)Data.buffer)->Field = Field;
} // end namespace clang.
+namespace llvm {
+template<> struct DenseMapInfo<clang::APValue::LValueBase> {
+ static clang::APValue::LValueBase getEmptyKey();
+ static clang::APValue::LValueBase getTombstoneKey();
+ static unsigned getHashValue(const clang::APValue::LValueBase &Base);
+ static bool isEqual(const clang::APValue::LValueBase &LHS,
+ const clang::APValue::LValueBase &RHS);
+};
+}
+
#endif
namespace {
struct LVBase {
- llvm::PointerIntPair<APValue::LValueBase, 1, bool> BaseAndIsOnePastTheEnd;
+ APValue::LValueBase Base;
CharUnits Offset;
unsigned PathLength;
- unsigned CallIndex;
- bool IsNullPtr;
+ bool IsNullPtr : 1;
+ bool IsOnePastTheEnd : 1;
};
}
+void *APValue::LValueBase::getOpaqueValue() const {
+ return Ptr.getOpaqueValue();
+}
+
+bool APValue::LValueBase::isNull() const {
+ return Ptr.isNull();
+}
+
+APValue::LValueBase::operator bool () const {
+ return static_cast<bool>(Ptr);
+}
+
+clang::APValue::LValueBase
+llvm::DenseMapInfo<clang::APValue::LValueBase>::getEmptyKey() {
+ return clang::APValue::LValueBase(
+ DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getEmptyKey(),
+ DenseMapInfo<unsigned>::getEmptyKey(),
+ DenseMapInfo<unsigned>::getEmptyKey());
+}
+
+clang::APValue::LValueBase
+llvm::DenseMapInfo<clang::APValue::LValueBase>::getTombstoneKey() {
+ return clang::APValue::LValueBase(
+ DenseMapInfo<clang::APValue::LValueBase::PtrTy>::getTombstoneKey(),
+ DenseMapInfo<unsigned>::getTombstoneKey(),
+ DenseMapInfo<unsigned>::getTombstoneKey());
+}
+
+unsigned llvm::DenseMapInfo<clang::APValue::LValueBase>::getHashValue(
+ const clang::APValue::LValueBase &Base) {
+ llvm::FoldingSetNodeID ID;
+ ID.AddPointer(Base.getOpaqueValue());
+ ID.AddInteger(Base.getCallIndex());
+ ID.AddInteger(Base.getVersion());
+ return ID.ComputeHash();
+}
+
+bool llvm::DenseMapInfo<clang::APValue::LValueBase>::isEqual(
+ const clang::APValue::LValueBase &LHS,
+ const clang::APValue::LValueBase &RHS) {
+ return LHS == RHS;
+}
+
struct APValue::LV : LVBase {
static const unsigned InlinePathSpace =
(DataSize - sizeof(LVBase)) / sizeof(LValuePathEntry);
MakeLValue();
if (RHS.hasLValuePath())
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(),
- RHS.isLValueOnePastTheEnd(), RHS.getLValueCallIndex(),
- RHS.isNullPointer());
+ RHS.isLValueOnePastTheEnd(), RHS.isNullPointer());
else
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(),
- RHS.getLValueCallIndex(), RHS.isNullPointer());
+ RHS.isNullPointer());
break;
case Array:
MakeArray(RHS.getArrayInitializedElts(), RHS.getArraySize());
const APValue::LValueBase APValue::getLValueBase() const {
assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const void*)Data.buffer)->BaseAndIsOnePastTheEnd.getPointer();
+ return ((const LV*)(const void*)Data.buffer)->Base;
}
bool APValue::isLValueOnePastTheEnd() const {
assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const void*)Data.buffer)->BaseAndIsOnePastTheEnd.getInt();
+ return ((const LV*)(const void*)Data.buffer)->IsOnePastTheEnd;
}
CharUnits &APValue::getLValueOffset() {
unsigned APValue::getLValueCallIndex() const {
assert(isLValue() && "Invalid accessor");
- return ((const LV*)(const char*)Data.buffer)->CallIndex;
+ return ((const LV*)(const char*)Data.buffer)->Base.getCallIndex();
+}
+
+unsigned APValue::getLValueVersion() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const char*)Data.buffer)->Base.getVersion();
}
bool APValue::isNullPointer() const {
}
void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
- unsigned CallIndex, bool IsNullPtr) {
+ bool IsNullPtr) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data.buffer);
- LVal.BaseAndIsOnePastTheEnd.setPointer(B);
- LVal.BaseAndIsOnePastTheEnd.setInt(false);
+ LVal.Base = B;
+ LVal.IsOnePastTheEnd = false;
LVal.Offset = O;
- LVal.CallIndex = CallIndex;
LVal.resizePath((unsigned)-1);
LVal.IsNullPtr = IsNullPtr;
}
void APValue::setLValue(LValueBase B, const CharUnits &O,
ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd,
- unsigned CallIndex, bool IsNullPtr) {
+ bool IsNullPtr) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data.buffer);
- LVal.BaseAndIsOnePastTheEnd.setPointer(B);
- LVal.BaseAndIsOnePastTheEnd.setInt(IsOnePastTheEnd);
+ LVal.Base = B;
+ LVal.IsOnePastTheEnd = IsOnePastTheEnd;
LVal.Offset = O;
- LVal.CallIndex = CallIndex;
LVal.resizePath(Path.size());
memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));
LVal.IsNullPtr = IsNullPtr;
// Note that we intentionally use std::map here so that references to
// values are stable.
- typedef std::map<const void*, APValue> MapTy;
- typedef MapTy::const_iterator temp_iterator;
+ typedef std::pair<const void *, unsigned> MapKeyTy;
+ typedef std::map<MapKeyTy, APValue> MapTy;
/// Temporaries - Temporary lvalues materialized within this stack frame.
MapTy Temporaries;
/// Index - The call index of this call.
unsigned Index;
+ /// The stack of integers for tracking version numbers for temporaries.
+ SmallVector<unsigned, 2> TempVersionStack = {1};
+ unsigned CurTempVersion = TempVersionStack.back();
+
+ unsigned getTempVersion() const { return TempVersionStack.back(); }
+
+ void pushTempVersion() {
+ TempVersionStack.push_back(++CurTempVersion);
+ }
+
+ void popTempVersion() {
+ TempVersionStack.pop_back();
+ }
+
// FIXME: Adding this to every 'CallStackFrame' may have a nontrivial impact
// on the overall stack usage of deeply-recursing constexpr evaluataions.
// (We should cache this map rather than recomputing it repeatedly.)
APValue *Arguments);
~CallStackFrame();
- APValue *getTemporary(const void *Key) {
- MapTy::iterator I = Temporaries.find(Key);
- return I == Temporaries.end() ? nullptr : &I->second;
+ // Return the temporary for Key whose version number is Version.
+ APValue *getTemporary(const void *Key, unsigned Version) {
+ MapKeyTy KV(Key, Version);
+ auto LB = Temporaries.lower_bound(KV);
+ if (LB != Temporaries.end() && LB->first == KV)
+ return &LB->second;
+ // Pair (Key,Version) wasn't found in the map. Check that no elements
+ // in the map have 'Key' as their key.
+ assert((LB == Temporaries.end() || LB->first.first != Key) &&
+ (LB == Temporaries.begin() || std::prev(LB)->first.first != Key) &&
+ "Element with key 'Key' found in map");
+ return nullptr;
}
+
+ // Return the current temporary for Key in the map.
+ APValue *getCurrentTemporary(const void *Key) {
+ auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
+ if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
+ return &std::prev(UB)->second;
+ return nullptr;
+ }
+
+ // Return the version number of the current temporary for Key.
+ unsigned getCurrentTemporaryVersion(const void *Key) const {
+ auto UB = Temporaries.upper_bound(MapKeyTy(Key, UINT_MAX));
+ if (UB != Temporaries.begin() && std::prev(UB)->first.first == Key)
+ return std::prev(UB)->first.second;
+ return 0;
+ }
+
APValue &createTemporary(const void *Key, bool IsLifetimeExtended);
};
/// EvaluatingObject - Pair of the AST node that an lvalue represents and
/// the call index that that lvalue was allocated in.
- typedef std::pair<APValue::LValueBase, unsigned> EvaluatingObject;
+ typedef std::pair<APValue::LValueBase, std::pair<unsigned, unsigned>>
+ EvaluatingObject;
/// EvaluatingConstructors - Set of objects that are currently being
/// constructed.
}
};
- bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex) {
- return EvaluatingConstructors.count(EvaluatingObject(Decl, CallIndex));
+ bool isEvaluatingConstructor(APValue::LValueBase Decl, unsigned CallIndex,
+ unsigned Version) {
+ return EvaluatingConstructors.count(
+ EvaluatingObject(Decl, {CallIndex, Version}));
}
/// The current array initialization index, if we're performing array
void setEvaluatingDecl(APValue::LValueBase Base, APValue &Value) {
EvaluatingDecl = Base;
EvaluatingDeclValue = &Value;
- EvaluatingConstructors.insert({Base, 0});
+ EvaluatingConstructors.insert({Base, {0, 0}});
}
const LangOptions &getLangOpts() const { return Ctx.getLangOpts(); }
unsigned OldStackSize;
public:
ScopeRAII(EvalInfo &Info)
- : Info(Info), OldStackSize(Info.CleanupStack.size()) {}
+ : Info(Info), OldStackSize(Info.CleanupStack.size()) {
+ // Push a new temporary version. This is needed to distinguish between
+ // temporaries created in different iterations of a loop.
+ Info.CurrentCall->pushTempVersion();
+ }
~ScopeRAII() {
// Body moved to a static method to encourage the compiler to inline away
// instances of this class.
cleanup(Info, OldStackSize);
+ Info.CurrentCall->popTempVersion();
}
private:
static void cleanup(EvalInfo &Info, unsigned OldStackSize) {
APValue &CallStackFrame::createTemporary(const void *Key,
bool IsLifetimeExtended) {
- APValue &Result = Temporaries[Key];
+ unsigned Version = Info.CurrentCall->getTempVersion();
+ APValue &Result = Temporaries[MapKeyTy(Key, Version)];
assert(Result.isUninit() && "temporary created multiple times");
Info.CleanupStack.push_back(Cleanup(&Result, IsLifetimeExtended));
return Result;
struct LValue {
APValue::LValueBase Base;
CharUnits Offset;
- unsigned InvalidBase : 1;
- unsigned CallIndex : 31;
SubobjectDesignator Designator;
- bool IsNullPtr;
+ bool IsNullPtr : 1;
+ bool InvalidBase : 1;
const APValue::LValueBase getLValueBase() const { return Base; }
CharUnits &getLValueOffset() { return Offset; }
const CharUnits &getLValueOffset() const { return Offset; }
- unsigned getLValueCallIndex() const { return CallIndex; }
SubobjectDesignator &getLValueDesignator() { return Designator; }
const SubobjectDesignator &getLValueDesignator() const { return Designator;}
bool isNullPointer() const { return IsNullPtr;}
+ unsigned getLValueCallIndex() const { return Base.getCallIndex(); }
+ unsigned getLValueVersion() const { return Base.getVersion(); }
+
void moveInto(APValue &V) const {
if (Designator.Invalid)
- V = APValue(Base, Offset, APValue::NoLValuePath(), CallIndex,
- IsNullPtr);
+ V = APValue(Base, Offset, APValue::NoLValuePath(), IsNullPtr);
else {
assert(!InvalidBase && "APValues can't handle invalid LValue bases");
V = APValue(Base, Offset, Designator.Entries,
- Designator.IsOnePastTheEnd, CallIndex, IsNullPtr);
+ Designator.IsOnePastTheEnd, IsNullPtr);
}
}
void setFrom(ASTContext &Ctx, const APValue &V) {
Base = V.getLValueBase();
Offset = V.getLValueOffset();
InvalidBase = false;
- CallIndex = V.getLValueCallIndex();
Designator = SubobjectDesignator(Ctx, V);
IsNullPtr = V.isNullPointer();
}
- void set(APValue::LValueBase B, unsigned I = 0, bool BInvalid = false) {
+ void set(APValue::LValueBase B, bool BInvalid = false) {
#ifndef NDEBUG
// We only allow a few types of invalid bases. Enforce that here.
if (BInvalid) {
Base = B;
Offset = CharUnits::fromQuantity(0);
InvalidBase = BInvalid;
- CallIndex = I;
Designator = SubobjectDesignator(getType(B));
IsNullPtr = false;
}
Base = (Expr *)nullptr;
Offset = CharUnits::fromQuantity(TargetVal);
InvalidBase = false;
- CallIndex = 0;
Designator = SubobjectDesignator(PointerTy->getPointeeType());
IsNullPtr = true;
}
void setInvalid(APValue::LValueBase B, unsigned I = 0) {
- set(B, I, true);
+ set(B, true);
}
// Check that this LValue is not based on a null pointer. If it is, produce
// Misc utilities
//===----------------------------------------------------------------------===//
+/// A helper function to create a temporary and set an LValue.
+template <class KeyTy>
+static APValue &createTemporary(const KeyTy *Key, bool IsLifetimeExtended,
+ LValue &LV, CallStackFrame &Frame) {
+ LV.set({Key, Frame.Info.CurrentCall->Index,
+ Frame.Info.CurrentCall->getTempVersion()});
+ return Frame.createTemporary(Key, IsLifetimeExtended);
+}
+
/// Negate an APSInt in place, converting it to a signed form if necessary, and
/// preserving its value (by extending by up to one bit as needed).
static void negateAsSigned(APSInt &Int) {
}
static bool IsLiteralLValue(const LValue &Value) {
- if (Value.CallIndex)
+ if (Value.getLValueCallIndex())
return false;
const Expr *E = Value.Base.dyn_cast<const Expr*>();
return E && !isa<MaterializeTemporaryExpr>(E);
/// \param Result Filled in with a pointer to the value of the variable.
static bool evaluateVarDeclInit(EvalInfo &Info, const Expr *E,
const VarDecl *VD, CallStackFrame *Frame,
- APValue *&Result) {
+ APValue *&Result, const LValue *LVal) {
// If this is a parameter to an active constexpr function call, perform
// argument substitution.
// If this is a local variable, dig out its value.
if (Frame) {
- Result = Frame->getTemporary(VD);
+ Result = LVal ? Frame->getTemporary(VD, LVal->getLValueVersion())
+ : Frame->getCurrentTemporary(VD);
if (!Result) {
// Assume variables referenced within a lambda's call operator that were
// not declared within the call operator are captures and during checking
}
CallStackFrame *Frame = nullptr;
- if (LVal.CallIndex) {
- Frame = Info.getCallFrame(LVal.CallIndex);
+ if (LVal.getLValueCallIndex()) {
+ Frame = Info.getCallFrame(LVal.getLValueCallIndex());
if (!Frame) {
Info.FFDiag(E, diag::note_constexpr_lifetime_ended, 1)
<< AK << LVal.Base.is<const ValueDecl*>();
}
}
- if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal))
+ if (!evaluateVarDeclInit(Info, E, VD, Frame, BaseVal, &LVal))
return CompleteObject();
} else {
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
return CompleteObject();
}
} else {
- BaseVal = Frame->getTemporary(Base);
+ BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
assert(BaseVal && "missing value for temporary");
}
// During the construction of an object, it is not yet 'const'.
// FIXME: This doesn't do quite the right thing for const subobjects of the
// object under construction.
- if (Info.isEvaluatingConstructor(LVal.getLValueBase(), LVal.CallIndex)) {
+ if (Info.isEvaluatingConstructor(LVal.getLValueBase(),
+ LVal.getLValueCallIndex(),
+ LVal.getLValueVersion())) {
BaseType = Info.Ctx.getCanonicalType(BaseType);
BaseType.removeLocalConst();
LifetimeStartedInEvaluation = true;
// Check for special cases where there is no existing APValue to look at.
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
- if (Base && !LVal.CallIndex && !Type.isVolatileQualified()) {
+ if (Base && !LVal.getLValueCallIndex() && !Type.isVolatileQualified()) {
if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) {
// In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
// initializer until now for such expressions. Such an expression can't be
return true;
LValue Result;
- Result.set(VD, Info.CurrentCall->Index);
- APValue &Val = Info.CurrentCall->createTemporary(VD, true);
+ APValue &Val = createTemporary(VD, true, Result, *Info.CurrentCall);
const Expr *InitE = VD->getInit();
if (!InitE) {
/// The location containing the result, if any (used to support RVO).
const LValue *Slot;
};
+
+struct TempVersionRAII {
+ CallStackFrame &Frame;
+
+ TempVersionRAII(CallStackFrame &Frame) : Frame(Frame) {
+ Frame.pushTempVersion();
+ }
+
+ ~TempVersionRAII() {
+ Frame.popTempVersion();
+ }
+};
+
}
static EvalStmtResult EvaluateStmt(StmtResult &Result, EvalInfo &Info,
}
EvalInfo::EvaluatingConstructorRAII EvalObj(
- Info, {This.getLValueBase(), This.CallIndex});
+ Info, {This.getLValueBase(),
+ {This.getLValueCallIndex(), This.getLValueVersion()}});
CallStackFrame Frame(Info, CallLoc, Definition, &This, ArgValues);
// FIXME: Creating an APValue just to hold a nonexistent return value is
{ return StmtVisitorTy::Visit(E->getResultExpr()); }
bool VisitSubstNonTypeTemplateParmExpr(const SubstNonTypeTemplateParmExpr *E)
{ return StmtVisitorTy::Visit(E->getReplacement()); }
- bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E)
- { return StmtVisitorTy::Visit(E->getExpr()); }
+ bool VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) {
+ TempVersionRAII RAII(*Info.CurrentCall);
+ return StmtVisitorTy::Visit(E->getExpr());
+ }
bool VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) {
+ TempVersionRAII RAII(*Info.CurrentCall);
// The initializer may not have been parsed yet, or might be erroneous.
if (!E->getExpr())
return Error(E);
}
bool VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
- if (APValue *Value = Info.CurrentCall->getTemporary(E))
+ if (APValue *Value = Info.CurrentCall->getCurrentTemporary(E))
return DerivedSuccess(*Value, E);
const Expr *Source = E->getSourceExpr();
if (!VD->getType()->isReferenceType()) {
if (Frame) {
- Result.set(VD, Frame->Index);
+ Result.set({VD, Frame->Index,
+ Info.CurrentCall->getCurrentTemporaryVersion(VD)});
return true;
}
return Success(VD);
}
APValue *V;
- if (!evaluateVarDeclInit(Info, E, VD, Frame, V))
+ if (!evaluateVarDeclInit(Info, E, VD, Frame, V, nullptr))
return false;
if (V->isUninit()) {
if (!Info.checkingPotentialConstantExpression())
*Value = APValue();
Result.set(E);
} else {
- Value = &Info.CurrentCall->
- createTemporary(E, E->getStorageDuration() == SD_Automatic);
- Result.set(E, Info.CurrentCall->Index);
+ Value = &createTemporary(E, E->getStorageDuration() == SD_Automatic, Result,
+ *Info.CurrentCall);
}
QualType Type = Inner->getType();
Result.Base = (Expr*)nullptr;
Result.InvalidBase = false;
Result.Offset = CharUnits::fromQuantity(N);
- Result.CallIndex = 0;
Result.Designator.setInvalid();
Result.IsNullPtr = false;
return true;
if (!evaluateLValue(SubExpr, Result))
return false;
} else {
- Result.set(SubExpr, Info.CurrentCall->Index);
- if (!EvaluateInPlace(Info.CurrentCall->createTemporary(SubExpr, false),
- Info, Result, SubExpr))
+ APValue &Value = createTemporary(SubExpr, false, Result,
+ *Info.CurrentCall);
+ if (!EvaluateInPlace(Value, Info, Result, SubExpr))
return false;
}
// The result is a pointer to the first element of the array.
/// Visit an expression which constructs the value of this temporary.
bool VisitConstructExpr(const Expr *E) {
- Result.set(E, Info.CurrentCall->Index);
- return EvaluateInPlace(Info.CurrentCall->createTemporary(E, false),
- Info, Result, E);
+ APValue &Value = createTemporary(E, false, Result, *Info.CurrentCall);
+ return EvaluateInPlace(Value, Info, Result, E);
}
bool VisitCastExpr(const CastExpr *E) {
}
return IsGlobalLValue(A.getLValueBase()) ||
- A.getLValueCallIndex() == B.getLValueCallIndex();
+ (A.getLValueCallIndex() == B.getLValueCallIndex() &&
+ A.getLValueVersion() == B.getLValueVersion());
}
/// \brief Determine whether this is a pointer past the end of the complete
return true;
} else if (T->isArrayType()) {
LValue LV;
- LV.set(E, Info.CurrentCall->Index);
- APValue &Value = Info.CurrentCall->createTemporary(E, false);
+ APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall);
if (!EvaluateArray(E, LV, Value, Info))
return false;
Result = Value;
} else if (T->isRecordType()) {
LValue LV;
- LV.set(E, Info.CurrentCall->Index);
- APValue &Value = Info.CurrentCall->createTemporary(E, false);
+ APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall);
if (!EvaluateRecord(E, LV, Value, Info))
return false;
Result = Value;
QualType Unqual = T.getAtomicUnqualifiedType();
if (Unqual->isArrayType() || Unqual->isRecordType()) {
LValue LV;
- LV.set(E, Info.CurrentCall->Index);
- APValue &Value = Info.CurrentCall->createTemporary(E, false);
+ APValue &Value = createTemporary(E, false, LV, *Info.CurrentCall);
if (!EvaluateAtomic(E, &LV, Value, Info))
return false;
} else {
// is a temporary being used as the 'this' pointer.
LValue This;
ImplicitValueInitExpr VIE(RD ? Info.Ctx.getRecordType(RD) : Info.Ctx.IntTy);
- This.set(&VIE, Info.CurrentCall->Index);
+ This.set({&VIE, Info.CurrentCall->Index});
ArrayRef<const Expr*> Args;