Add support for declaring pointers to members.
Add serialization support for ReferenceType.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@62934 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index d20387d..f3243c2 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -85,6 +85,7 @@
   unsigned NumBuiltin = 0, NumPointer = 0, NumArray = 0, NumFunctionP = 0;
   unsigned NumVector = 0, NumComplex = 0, NumBlockPointer = 0;
   unsigned NumFunctionNP = 0, NumTypeName = 0, NumTagged = 0, NumReference = 0;
+  unsigned NumMemberPointer = 0;
   
   unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 0;
   unsigned NumObjCInterfaces = 0, NumObjCQualifiedInterfaces = 0;
@@ -101,6 +102,8 @@
       ++NumBlockPointer;
     else if (isa<ReferenceType>(T))
       ++NumReference;
+    else if (isa<MemberPointerType>(T))
+      ++NumMemberPointer;
     else if (isa<ComplexType>(T))
       ++NumComplex;
     else if (isa<ArrayType>(T))
@@ -142,6 +145,7 @@
   fprintf(stderr, "    %d pointer types\n", NumPointer);
   fprintf(stderr, "    %d block pointer types\n", NumBlockPointer);
   fprintf(stderr, "    %d reference types\n", NumReference);
+  fprintf(stderr, "    %d member pointer types\n", NumMemberPointer);
   fprintf(stderr, "    %d complex types\n", NumComplex);
   fprintf(stderr, "    %d array types\n", NumArray);
   fprintf(stderr, "    %d vector types\n", NumVector);
@@ -164,6 +168,7 @@
   fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+
     NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+
     NumComplex*sizeof(ComplexType)+NumVector*sizeof(VectorType)+
+    NumMemberPointer*sizeof(MemberPointerType)+
     NumFunctionP*sizeof(FunctionTypeProto)+
     NumFunctionNP*sizeof(FunctionTypeNoProto)+
     NumTypeName*sizeof(TypedefType)+NumTagged*sizeof(TagType)+
@@ -374,7 +379,19 @@
     // FIXME: This is wrong for struct layout: a reference in a struct has
     // pointer size.
     return getTypeInfo(cast<ReferenceType>(T)->getPointeeType());
-    
+  case Type::MemberPointer: {
+    // Note that this is not only platform- but also ABI-dependent. We follow
+    // the GCC ABI, where pointers to data are one pointer large, pointers to
+    // functions two pointers. But if we want to support ABI compatibility with
+    // other compilers too, we need to delegate this completely to TargetInfo.
+    QualType Pointee = cast<MemberPointerType>(T)->getPointeeType();
+    unsigned AS = Pointee.getAddressSpace();
+    Width = Target.getPointerWidth(AS);
+    if (Pointee->isFunctionType())
+      Width *= 2;
+    Align = Target.getPointerAlign(AS);
+    // GCC aligns at single pointer width.
+  }
   case Type::Complex: {
     // Complex types have the same alignment as their elements, but twice the
     // size.
@@ -808,6 +825,38 @@
   return QualType(New, 0);
 }
 
+/// getMemberPointerType - Return the uniqued reference to the type for a
+/// member pointer to the specified type, in the specified class.
+QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls)
+{
+  // Unique pointers, to guarantee there is only one pointer of a particular
+  // structure.
+  llvm::FoldingSetNodeID ID;
+  MemberPointerType::Profile(ID, T, Cls);
+
+  void *InsertPos = 0;
+  if (MemberPointerType *PT =
+      MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos))
+    return QualType(PT, 0);
+
+  // If the pointee or class type isn't canonical, this won't be a canonical
+  // type either, so fill in the canonical type field.
+  QualType Canonical;
+  if (!T->isCanonical()) {
+    Canonical = getMemberPointerType(getCanonicalType(T),getCanonicalType(Cls));
+
+    // Get the new insert position for the node we care about.
+    MemberPointerType *NewIP =
+      MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos);
+    assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP;
+  }
+  void *Mem = Allocator.Allocate(sizeof(MemberPointerType), 8);
+  MemberPointerType *New = new (Mem) MemberPointerType(T, Cls, Canonical);
+  Types.push_back(New);
+  MemberPointerTypes.InsertNode(New, InsertPos);
+  return QualType(New, 0);
+}
+
 /// getConstantArrayType - Return the unique reference to the type for an 
 /// array of the specified element type.
 QualType ASTContext::getConstantArrayType(QualType EltTy, 
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 9496892..ebaa011 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -288,6 +288,24 @@
   return getDesugaredType()->getAsReferenceType();
 }
 
+const MemberPointerType *Type::getAsMemberPointerType() const {
+  // If this is directly a member pointer type, return it.
+  if (const MemberPointerType *MTy = dyn_cast<MemberPointerType>(this))
+    return MTy;
+
+  // If the canonical form of this type isn't the right kind, reject it.
+  if (!isa<MemberPointerType>(CanonicalType)) {
+    // Look through type qualifiers
+    if (isa<MemberPointerType>(CanonicalType.getUnqualifiedType()))
+      return CanonicalType.getUnqualifiedType()->getAsMemberPointerType();
+    return 0;
+  }
+
+  // If this is a typedef for a member pointer type, strip the typedef off
+  // without losing all typedef information.
+  return getDesugaredType()->getAsMemberPointerType();
+}
+
 /// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length
 /// array types and types that contain variable array types in their
 /// declarator
@@ -300,8 +318,11 @@
   if (const Type *T = getArrayElementTypeNoTypeQual())
     return T->isVariablyModifiedType();
 
-  // A pointer can point to a variably modified type
-  if (const PointerType *PT = getAsPointerType())
+  // A pointer can point to a variably modified type.
+  // Also, C++ references and member pointers can point to a variably modified
+  // type, where VLAs appear as an extension to C++, and should be treated
+  // correctly.
+  if (const PointerLikeType *PT = getAsPointerLikeType())
     return PT->getPointeeType()->isVariablyModifiedType();
 
   // A function can return a variably modified type
@@ -633,6 +654,7 @@
     return ASQT->getBaseType()->isScalarType();
   return isa<PointerType>(CanonicalType) ||
          isa<BlockPointerType>(CanonicalType) ||
+         isa<MemberPointerType>(CanonicalType) ||
          isa<ComplexType>(CanonicalType) ||
          isa<ObjCQualifiedIdType>(CanonicalType);
 }
@@ -702,9 +724,9 @@
   case Builtin:
   case Complex:
   case Pointer:
+  case MemberPointer:
   case Vector:
   case ExtVector:
-    // FIXME: pointer-to-member
     return true;
 
   case Tagged:
@@ -951,6 +973,20 @@
   getPointeeType().getAsStringInternal(S);
 }
 
+void MemberPointerType::getAsStringInternal(std::string &S) const {
+  std::string C;
+  Class->getAsStringInternal(C);
+  C += "::*";
+  S = C + S;
+
+  // Handle things like 'int (&A)[4];' correctly.
+  // FIXME: this should include vectors, but vectors use attributes I guess.
+  if (isa<ArrayType>(getPointeeType()))
+    S = '(' + S + ')';
+
+  getPointeeType().getAsStringInternal(S);
+}
+
 void ConstantArrayType::getAsStringInternal(std::string &S) const {
   S += '[';
   S += llvm::utostr(getSize().getZExtValue());
diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp
index 4f3eeca..12c3d03 100644
--- a/lib/AST/TypeSerialization.cpp
+++ b/lib/AST/TypeSerialization.cpp
@@ -93,21 +93,29 @@
     case Type::IncompleteArray:
       D.RegisterPtr(PtrID,IncompleteArrayType::CreateImpl(Context,D));
       break;
-      
+
+    case Type::MemberPointer:
+      D.RegisterPtr(PtrID, MemberPointerType::CreateImpl(Context, D));
+      break;
+
     case Type::Pointer:
-      D.RegisterPtr(PtrID,PointerType::CreateImpl(Context,D));
+      D.RegisterPtr(PtrID, PointerType::CreateImpl(Context, D));
       break;
 
     case Type::BlockPointer:
-      D.RegisterPtr(PtrID,BlockPointerType::CreateImpl(Context,D));
+      D.RegisterPtr(PtrID, BlockPointerType::CreateImpl(Context, D));
       break;
-      
+
+    case Type::Reference:
+      D.RegisterPtr(PtrID, ReferenceType::CreateImpl(Context, D));
+      break;
+
     case Type::Tagged:
-      D.RegisterPtr(PtrID,TagType::CreateImpl(Context,D));
+      D.RegisterPtr(PtrID, TagType::CreateImpl(Context, D));
       break;
-      
+
     case Type::TypeName:
-      D.RegisterPtr(PtrID,TypedefType::CreateImpl(Context,D));
+      D.RegisterPtr(PtrID, TypedefType::CreateImpl(Context, D));
       break;
 
     case Type::TypeOfExp:
@@ -123,7 +131,7 @@
       break;
 
     case Type::VariableArray:
-      D.RegisterPtr(PtrID,VariableArrayType::CreateImpl(Context,D));
+      D.RegisterPtr(PtrID, VariableArrayType::CreateImpl(Context, D));
       break;
   }
 }
@@ -243,6 +251,33 @@
 }
 
 //===----------------------------------------------------------------------===//
+// ReferenceType
+//===----------------------------------------------------------------------===//
+
+void ReferenceType::EmitImpl(Serializer& S) const {
+  S.Emit(getPointeeType());
+}
+
+Type* ReferenceType::CreateImpl(ASTContext& Context, Deserializer& D) {
+  return Context.getReferenceType(QualType::ReadVal(D)).getTypePtr();
+}
+
+//===----------------------------------------------------------------------===//
+// MemberPointerType
+//===----------------------------------------------------------------------===//
+
+void MemberPointerType::EmitImpl(Serializer& S) const {
+  S.Emit(getPointeeType());
+  S.Emit(QualType(Class, 0));
+}
+
+Type* MemberPointerType::CreateImpl(ASTContext& Context, Deserializer& D) {
+  QualType Pointee = QualType::ReadVal(D);
+  QualType Class = QualType::ReadVal(D);
+  return Context.getMemberPointerType(Pointee, Class.getTypePtr()).getTypePtr();
+}
+
+//===----------------------------------------------------------------------===//
 // TagType
 //===----------------------------------------------------------------------===//