svn commit: r489225 - in head/devel/llvm60: . files/clang
Brooks Davis
brooks at FreeBSD.org
Thu Jan 3 21:16:58 UTC 2019
Author: brooks
Date: Thu Jan 3 21:16:57 2019
New Revision: 489225
URL: https://svnweb.freebsd.org/changeset/ports/489225
Log:
Add a patch files for stable/12 r342281, which corresponds to the
following upstream revision:
https://reviews.llvm.org/rL329671
This fixes 'Assertion failed: (Result.isUninit() && "temporary created
multiple times"), function createTemporary' errors (if assertions are
enabled, otherwise the compiler internal state might go bad), when
building the graphics/rawtherapee port.
Submitted by: dim
Differential Revision: https://reviews.freebsd.org/D18699
Added:
head/devel/llvm60/files/clang/patch-stable12-r342281.diff (contents, props changed)
Modified:
head/devel/llvm60/Makefile
Modified: head/devel/llvm60/Makefile
==============================================================================
--- head/devel/llvm60/Makefile Thu Jan 3 21:08:51 2019 (r489224)
+++ head/devel/llvm60/Makefile Thu Jan 3 21:16:57 2019 (r489225)
@@ -2,7 +2,7 @@
PORTNAME= llvm
DISTVERSION= 6.0.1
-PORTREVISION= 4
+PORTREVISION= 5
CATEGORIES= devel lang
MASTER_SITES= http://${PRE_}releases.llvm.org/${LLVM_RELEASE}/${RCDIR}
PKGNAMESUFFIX= ${LLVM_SUFFIX}
Added: head/devel/llvm60/files/clang/patch-stable12-r342281.diff
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/devel/llvm60/files/clang/patch-stable12-r342281.diff Thu Jan 3 21:16:57 2019 (r489225)
@@ -0,0 +1,834 @@
+r342281 | dim | 2018-12-20 19:28:53 +0100 (Thu, 20 Dec 2018) | 24 lines
+
+Pull in r329671 from upstream clang trunk (by Akira Hatanaka):
+
+ [ExprConstant] Use an AST node and a version number as a key to
+ create an APValue and retrieve it from map Temporaries.
+
+ The version number is needed when a single AST node is visited
+ multiple times and is used to create APValues that are required to be
+ distinct from each other (for example, MaterializeTemporaryExprs in
+ default arguments and VarDecls in loops).
+
+ rdar://problem/36505742
+
+ Differential Revision: https://reviews.llvm.org/D42776
+
+This should fix 'Assertion failed: (Result.isUninit() && "temporary
+created multiple times"), function createTemporary' errors (if
+assertions are enabled, otherwise the compiler internal state might go
+bad), when building the graphics/rawtherapee port.
+
+Direct commit to stable/11 and stable/12, since head already has clang
+7.0.1, which includes this change.
+
+PR: 234144
+
+Index: tools/clang/include/clang/AST/APValue.h
+===================================================================
+--- tools/clang/include/clang/AST/APValue.h (revision 342280)
++++ tools/clang/include/clang/AST/APValue.h (revision 342281)
+@@ -53,7 +53,58 @@ class APValue {
+ 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
+@@ -135,15 +186,15 @@ class APValue {
+ }
+ 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);
+@@ -255,6 +306,7 @@ class APValue {
+ bool hasLValuePath() const;
+ ArrayRef<LValuePathEntry> getLValuePath() const;
+ unsigned getLValueCallIndex() const;
++ unsigned getLValueVersion() const;
+ bool isNullPointer() const;
+
+ APValue &getVectorElt(unsigned I) {
+@@ -376,10 +428,10 @@ class APValue {
+ ((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;
+@@ -451,4 +503,14 @@ class APValue {
+
+ } // 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
+Index: tools/clang/lib/AST/APValue.cpp
+===================================================================
+--- tools/clang/lib/AST/APValue.cpp (revision 342280)
++++ tools/clang/lib/AST/APValue.cpp (revision 342281)
+@@ -23,14 +23,57 @@ using namespace clang;
+
+ 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);
+@@ -150,11 +193,10 @@ APValue::APValue(const APValue &RHS) : Kind(Uninit
+ 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());
+@@ -552,12 +594,12 @@ std::string APValue::getAsString(ASTContext &Ctx,
+
+ 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() {
+@@ -578,9 +620,14 @@ ArrayRef<APValue::LValuePathEntry> APValue::getLVa
+
+ 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 {
+ assert(isLValue() && "Invalid usage");
+ return ((const LV*)(const char*)Data.buffer)->IsNullPtr;
+@@ -587,13 +634,12 @@ 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;
+ }
+@@ -600,13 +646,12 @@ void APValue::setLValue(LValueBase B, const CharUn
+
+ 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;
+Index: tools/clang/lib/AST/ExprConstant.cpp
+===================================================================
+--- tools/clang/lib/AST/ExprConstant.cpp (revision 342280)
++++ tools/clang/lib/AST/ExprConstant.cpp (revision 342281)
+@@ -446,8 +446,8 @@ namespace {
+
+ // 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;
+
+@@ -457,6 +457,20 @@ namespace {
+ /// 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.)
+@@ -473,10 +487,36 @@ namespace {
+ 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);
+ };
+
+@@ -606,7 +646,8 @@ namespace {
+
+ /// 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.
+@@ -625,8 +666,10 @@ namespace {
+ }
+ };
+
+- 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
+@@ -722,7 +765,7 @@ namespace {
+ 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(); }
+@@ -1086,11 +1129,16 @@ namespace {
+ 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) {
+@@ -1170,7 +1218,8 @@ CallStackFrame::~CallStackFrame() {
+
+ 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;
+@@ -1262,27 +1311,27 @@ namespace {
+ 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) {
+@@ -1290,12 +1339,11 @@ namespace {
+ 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) {
+@@ -1308,7 +1356,6 @@ namespace {
+ Base = B;
+ Offset = CharUnits::fromQuantity(0);
+ InvalidBase = BInvalid;
+- CallIndex = I;
+ Designator = SubobjectDesignator(getType(B));
+ IsNullPtr = false;
+ }
+@@ -1317,13 +1364,12 @@ namespace {
+ 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
+@@ -1525,6 +1571,15 @@ static bool EvaluateAsRValue(EvalInfo &Info, const
+ // 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) {
+@@ -1854,7 +1909,7 @@ static const ValueDecl *GetLValueBaseDecl(const LV
+ }
+
+ 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);
+@@ -2404,7 +2459,7 @@ static bool handleLValueToRValueConversion(EvalInf
+ /// \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.
+@@ -2423,7 +2478,8 @@ static bool evaluateVarDeclInit(EvalInfo &Info, co
+
+ // 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
+@@ -3000,8 +3056,8 @@ static CompleteObject findCompleteObject(EvalInfo
+ }
+
+ 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*>();
+@@ -3113,7 +3169,7 @@ static CompleteObject findCompleteObject(EvalInfo
+ }
+ }
+
+- 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*>();
+@@ -3155,7 +3211,7 @@ static CompleteObject findCompleteObject(EvalInfo
+ return CompleteObject();
+ }
+ } else {
+- BaseVal = Frame->getTemporary(Base);
++ BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
+ assert(BaseVal && "missing value for temporary");
+ }
+
+@@ -3175,7 +3231,9 @@ static CompleteObject findCompleteObject(EvalInfo
+ // 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();
+ }
+@@ -3212,7 +3270,7 @@ static bool handleLValueToRValueConversion(EvalInf
+
+ // 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
+@@ -3715,8 +3773,7 @@ static bool EvaluateVarDecl(EvalInfo &Info, const
+ 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) {
+@@ -3772,6 +3829,19 @@ struct StmtResult {
+ /// 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,
+@@ -4329,7 +4399,8 @@ static bool HandleConstructorCall(const Expr *E, c
+ }
+
+ 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
+@@ -4578,9 +4649,12 @@ class ExprEvaluatorBase
+ { 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);
+@@ -4658,7 +4732,7 @@ class ExprEvaluatorBase
+ }
+
+ 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();
+@@ -5216,7 +5290,8 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr
+
+ 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);
+@@ -5223,7 +5298,7 @@ bool LValueExprEvaluator::VisitVarDecl(const Expr
+ }
+
+ 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())
+@@ -5255,9 +5330,8 @@ bool LValueExprEvaluator::VisitMaterializeTemporar
+ *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();
+@@ -5736,7 +5810,6 @@ bool PointerExprEvaluator::VisitCastExpr(const Cas
+ Result.Base = (Expr*)nullptr;
+ Result.InvalidBase = false;
+ Result.Offset = CharUnits::fromQuantity(N);
+- Result.CallIndex = 0;
+ Result.Designator.setInvalid();
+ Result.IsNullPtr = false;
+ return true;
+@@ -5752,9 +5825,9 @@ bool PointerExprEvaluator::VisitCastExpr(const Cas
+ 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.
+@@ -6520,9 +6593,8 @@ class TemporaryExprEvaluator
+
+ /// 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) {
+@@ -8007,7 +8079,8 @@ static bool HasSameBase(const LValue &A, const LVa
+ }
+
+ 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
+@@ -9941,15 +10014,13 @@ static bool Evaluate(APValue &Result, EvalInfo &In
+ 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;
+@@ -9963,8 +10034,7 @@ static bool Evaluate(APValue &Result, EvalInfo &In
+ 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 {
+@@ -10786,7 +10856,7 @@ bool Expr::isPotentialConstantExpr(const FunctionD
+ // 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;
+
+Index: tools/clang/test/SemaCXX/constant-expression-cxx1y.cpp
+===================================================================
+--- tools/clang/test/SemaCXX/constant-expression-cxx1y.cpp (revision 342280)
++++ tools/clang/test/SemaCXX/constant-expression-cxx1y.cpp (revision 342281)
+@@ -852,7 +852,6 @@ namespace Lifetime {
+ static_assert(h(2) == 0, ""); // expected-error {{constant expression}} expected-note {{in call}}
+ static_assert(h(3) == 0, ""); // expected-error {{constant expression}} expected-note {{in call}}
+
+- // FIXME: This function should be treated as non-constant.
+ constexpr void lifetime_versus_loops() {
+ int *p = 0;
+ for (int i = 0; i != 2; ++i) {
+@@ -862,10 +861,10 @@ namespace Lifetime {
+ if (i)
+ // This modifies the 'n' from the previous iteration of the loop outside
+ // its lifetime.
+- ++*q;
++ ++*q; // expected-note {{increment of object outside its lifetime}}
+ }
+ }
+- static_assert((lifetime_versus_loops(), true), "");
++ static_assert((lifetime_versus_loops(), true), ""); // expected-error {{constant expression}} expected-note {{in call}}
+ }
+
+ namespace Bitfields {
+Index: tools/clang/test/SemaCXX/constexpr-default-arg.cpp
+===================================================================
+--- tools/clang/test/SemaCXX/constexpr-default-arg.cpp (nonexistent)
++++ tools/clang/test/SemaCXX/constexpr-default-arg.cpp (revision 342281)
+@@ -0,0 +1,38 @@
++// RUN: %clang_cc1 -std=c++1y -S -o - -emit-llvm -verify %s
++
++namespace default_arg_temporary {
++
++constexpr bool equals(const float& arg = 1.0f) {
++ return arg == 1.0f;
++}
++
++constexpr const int &x(const int &p = 0) {
++ return p;
++}
++
++struct S {
++ constexpr S(const int &a = 0) {}
++};
++
++void test_default_arg2() {
++ // This piece of code used to cause an assertion failure in
++ // CallStackFrame::createTemporary because the same MTE is used to initilize
++ // both elements of the array (see PR33140).
++ constexpr S s[2] = {};
++
++ // This piece of code used to cause an assertion failure in
++ // CallStackFrame::createTemporary because multiple CXXDefaultArgExpr share
++ // the same MTE (see PR33140).
++ static_assert(equals() && equals(), "");
++
++ // Test that constant expression evaluation produces distinct lvalues for
++ // each call.
++ static_assert(&x() != &x(), "");
++}
++
++// Check that multiple CXXDefaultInitExprs don't cause an assertion failure.
++struct A { int &&r = 0; }; // expected-warning {{binding reference member}} // expected-note {{reference member declared here}}
++struct B { A x, y; };
++B b = {};
++
++}
More information about the svn-ports-head
mailing list