Constant expression evaluation: add support for evaluation of member pointers
and base-to-derived casts, and add proper handling of temporaries.

llvm-svn: 144926
diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp
index 146ebad..b99a662 100644
--- a/clang/lib/AST/APValue.cpp
+++ b/clang/lib/AST/APValue.cpp
@@ -21,7 +21,7 @@
 
 namespace {
   struct LVBase {
-    APValue::LValueBase Base;
+    llvm::PointerIntPair<APValue::LValueBase, 1, bool> BaseAndIsOnePastTheEnd;
     CharUnits Offset;
     unsigned PathLength;
   };
@@ -40,12 +40,17 @@
   };
 
   LV() { PathLength = (unsigned)-1; }
-  ~LV() { if (hasPathPtr()) delete [] PathPtr; }
+  ~LV() { resizePath(0); }
 
-  void allocPath() {
-    if (hasPathPtr()) PathPtr = new LValuePathEntry[PathLength];
+  void resizePath(unsigned Length) {
+    if (Length == PathLength)
+      return;
+    if (hasPathPtr())
+      delete [] PathPtr;
+    PathLength = Length;
+    if (hasPathPtr())
+      PathPtr = new LValuePathEntry[Length];
   }
-  void freePath() { if (hasPathPtr()) delete [] PathPtr; }
 
   bool hasPath() const { return PathLength != (unsigned)-1; }
   bool hasPathPtr() const { return hasPath() && PathLength > InlinePathSpace; }
@@ -56,6 +61,43 @@
   }
 };
 
+namespace {
+  struct MemberPointerBase {
+    llvm::PointerIntPair<const ValueDecl*, 1, bool> MemberAndIsDerivedMember;
+    unsigned PathLength;
+  };
+}
+
+struct APValue::MemberPointerData : MemberPointerBase {
+  static const unsigned InlinePathSpace =
+      (MaxSize - sizeof(MemberPointerBase)) / sizeof(const CXXRecordDecl*);
+  typedef const CXXRecordDecl *PathElem;
+  union {
+    PathElem Path[InlinePathSpace];
+    PathElem *PathPtr;
+  };
+
+  MemberPointerData() { PathLength = 0; }
+  ~MemberPointerData() { resizePath(0); }
+
+  void resizePath(unsigned Length) {
+    if (Length == PathLength)
+      return;
+    if (hasPathPtr())
+      delete [] PathPtr;
+    PathLength = Length;
+    if (hasPathPtr())
+      PathPtr = new PathElem[Length];
+  }
+
+  bool hasPathPtr() const { return PathLength > InlinePathSpace; }
+
+  PathElem *getPath() { return hasPathPtr() ? PathPtr : Path; }
+  const PathElem *getPath() const {
+    return hasPathPtr() ? PathPtr : Path;
+  }
+};
+
 // FIXME: Reduce the malloc traffic here.
 
 APValue::Arr::Arr(unsigned NumElts, unsigned Size) :
@@ -78,7 +120,8 @@
 const APValue &APValue::operator=(const APValue &RHS) {
   if (this == &RHS)
     return *this;
-  if (Kind != RHS.Kind || Kind == Array || Kind == Struct) {
+  if (Kind != RHS.Kind || Kind == Array || Kind == Struct ||
+      Kind == MemberPointer) {
     MakeUninit();
     if (RHS.isInt())
       MakeInt();
@@ -98,6 +141,10 @@
       MakeStruct(RHS.getStructNumBases(), RHS.getStructNumFields());
     else if (RHS.isUnion())
       MakeUnion();
+    else if (RHS.isMemberPointer())
+      MakeMemberPointer(RHS.getMemberPointerDecl(),
+                        RHS.isMemberPointerToDerivedMember(),
+                        RHS.getMemberPointerPath());
   }
   if (isInt())
     setInt(RHS.getInt());
@@ -112,7 +159,8 @@
     setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag());
   else if (isLValue()) {
     if (RHS.hasLValuePath())
-      setLValue(RHS.getLValueBase(), RHS.getLValueOffset(),RHS.getLValuePath());
+      setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(),
+                RHS.isLValueOnePastTheEnd());
     else
       setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath());
   } else if (isArray()) {
@@ -149,6 +197,8 @@
     ((StructData*)(char*)Data)->~StructData();
   else if (Kind == Union)
     ((UnionData*)(char*)Data)->~UnionData();
+  else if (Kind == MemberPointer)
+    ((MemberPointerData*)(char*)Data)->~MemberPointerData();
   Kind = Uninitialized;
 }
 
@@ -217,6 +267,9 @@
   case Union:
     OS << "Union: " << getUnionValue();
     return;
+  case MemberPointer:
+    OS << "MemberPointer: <todo>";
+    return;
   }
   llvm_unreachable("Unknown APValue kind!");
 }
@@ -280,6 +333,9 @@
   case APValue::Union:
     Out << '{' << V.getUnionValue() << '}';
     return;
+  case APValue::MemberPointer:
+    Out << "MemberPointer: <todo>";
+    return;
   }
   llvm_unreachable("Unknown APValue kind!");
 }
@@ -294,7 +350,12 @@
 
 const APValue::LValueBase APValue::getLValueBase() const {
   assert(isLValue() && "Invalid accessor");
-  return ((const LV*)(const void*)Data)->Base;
+  return ((const LV*)(const void*)Data)->BaseAndIsOnePastTheEnd.getPointer();
+}
+
+bool APValue::isLValueOnePastTheEnd() const {
+  assert(isLValue() && "Invalid accessor");
+  return ((const LV*)(const void*)Data)->BaseAndIsOnePastTheEnd.getInt();
 }
 
 CharUnits &APValue::getLValueOffset() {
@@ -316,24 +377,41 @@
 void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath) {
   assert(isLValue() && "Invalid accessor");
   LV &LVal = *((LV*)(char*)Data);
-  LVal.freePath();
-  LVal.Base = B;
+  LVal.BaseAndIsOnePastTheEnd.setPointer(B);
+  LVal.BaseAndIsOnePastTheEnd.setInt(false);
   LVal.Offset = O;
-  LVal.PathLength = (unsigned)-1;
+  LVal.resizePath((unsigned)-1);
 }
 
 void APValue::setLValue(LValueBase B, const CharUnits &O,
-                        ArrayRef<LValuePathEntry> Path) {
+                        ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd) {
   assert(isLValue() && "Invalid accessor");
   LV &LVal = *((LV*)(char*)Data);
-  LVal.freePath();
-  LVal.Base = B;
+  LVal.BaseAndIsOnePastTheEnd.setPointer(B);
+  LVal.BaseAndIsOnePastTheEnd.setInt(IsOnePastTheEnd);
   LVal.Offset = O;
-  LVal.PathLength = Path.size();
-  LVal.allocPath();
+  LVal.resizePath(Path.size());
   memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));
 }
 
+const ValueDecl *APValue::getMemberPointerDecl() const {
+  assert(isMemberPointer() && "Invalid accessor");
+  const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+  return MPD.MemberAndIsDerivedMember.getPointer();
+}
+
+bool APValue::isMemberPointerToDerivedMember() const {
+  assert(isMemberPointer() && "Invalid accessor");
+  const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+  return MPD.MemberAndIsDerivedMember.getInt();
+}
+
+ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const {
+  assert(isMemberPointer() && "Invalid accessor");
+  const MemberPointerData &MPD = *((const MemberPointerData*)(const char*)Data);
+  return ArrayRef<const CXXRecordDecl*>(MPD.getPath(), MPD.PathLength);
+}
+
 void APValue::MakeLValue() {
   assert(isUninit() && "Bad state change");
   assert(sizeof(LV) <= MaxSize && "LV too big");
@@ -346,3 +424,14 @@
   new ((void*)(char*)Data) Arr(InitElts, Size);
   Kind = Array;
 }
+
+void APValue::MakeMemberPointer(const ValueDecl *Member, bool IsDerivedMember,
+                                ArrayRef<const CXXRecordDecl*> Path) {
+  assert(isUninit() && "Bad state change");
+  MemberPointerData *MPD = new ((void*)(char*)Data) MemberPointerData;
+  Kind = MemberPointer;
+  MPD->MemberAndIsDerivedMember.setPointer(Member);
+  MPD->MemberAndIsDerivedMember.setInt(IsDerivedMember);
+  MPD->resizePath(Path.size());
+  memcpy(MPD->getPath(), Path.data(), Path.size()*sizeof(const CXXRecordDecl*));
+}