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