[cfe-commits] r62934 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/Type.h include/clang/Basic/DiagnosticKinds.def include/clang/Parse/DeclSpec.h include/clang/Parse/Ownership.h lib/AST/ASTContext.cpp lib/AST/Type.cpp lib/AST/TypeSerialization.cpp lib/Parse/ParseDecl.cpp lib/Sema/SemaCXXScopeSpec.cpp lib/Sema/SemaType.cpp test/SemaCXX/member-pointer.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Sat Jan 24 13:16:56 PST 2009


Author: cornedbee
Date: Sat Jan 24 15:16:55 2009
New Revision: 62934

URL: http://llvm.org/viewvc/llvm-project?rev=62934&view=rev
Log:
Add support for declaring pointers to members.
Add serialization support for ReferenceType.

Added:
    cfe/trunk/test/SemaCXX/member-pointer.cpp
Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/Type.h
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/include/clang/Parse/DeclSpec.h
    cfe/trunk/include/clang/Parse/Ownership.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Type.cpp
    cfe/trunk/lib/AST/TypeSerialization.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
    cfe/trunk/lib/Sema/SemaType.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=62934&r1=62933&r2=62934&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Sat Jan 24 15:16:55 2009
@@ -60,6 +60,7 @@
   llvm::FoldingSet<PointerType> PointerTypes;
   llvm::FoldingSet<BlockPointerType> BlockPointerTypes;
   llvm::FoldingSet<ReferenceType> ReferenceTypes;
+  llvm::FoldingSet<MemberPointerType> MemberPointerTypes;
   llvm::FoldingSet<ConstantArrayType> ConstantArrayTypes;
   llvm::FoldingSet<IncompleteArrayType> IncompleteArrayTypes;
   std::vector<VariableArrayType*> VariableArrayTypes;
@@ -185,11 +186,16 @@
   /// getBlockPointerType - Return the uniqued reference to the type for a block
   /// of the specified type.
   QualType getBlockPointerType(QualType T);
-  
+
   /// getReferenceType - Return the uniqued reference to the type for a
   /// reference to the specified type.
   QualType getReferenceType(QualType T);
-  
+
+  /// getMemberPointerType - Return the uniqued reference to the type for a
+  /// member pointer to the specified type in the specified class. The class
+  /// is a Type because it could be a dependent name.
+  QualType getMemberPointerType(QualType T, const Type *Cls);
+
   /// getVariableArrayType - Returns a non-unique reference to the type for a
   /// variable array of the specified element type.
   QualType getVariableArrayType(QualType EltTy, Expr *NumElts,

Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=62934&r1=62933&r2=62934&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Sat Jan 24 15:16:55 2009
@@ -46,6 +46,7 @@
   class PointerType;
   class BlockPointerType;
   class ReferenceType;
+  class MemberPointerType;
   class VectorType;
   class ArrayType;
   class ConstantArrayType;
@@ -66,7 +67,7 @@
   class ObjCQualifiedIdType;
   class ObjCQualifiedInterfaceType;
   class StmtIteratorBase;
-  
+
 /// QualType - For efficiency, we don't store CVR-qualified types as nodes on
 /// their own: instead each reference to a type stores the qualifiers.  This
 /// greatly reduces the number of nodes we need to allocate for types (for
@@ -237,7 +238,7 @@
 class Type {
 public:
   enum TypeClass {
-    Builtin, Complex, Pointer, Reference, 
+    Builtin, Complex, Pointer, Reference, MemberPointer,
     ConstantArray, VariableArray, IncompleteArray, DependentSizedArray,
     Vector, ExtVector,
     FunctionNoProto, FunctionProto,
@@ -337,6 +338,8 @@
   bool isBlockPointerType() const;
   bool isReferenceType() const;
   bool isFunctionPointerType() const;
+  bool isMemberPointerType() const;
+  bool isMemberFunctionPointerType() const;
   bool isArrayType() const;
   bool isConstantArrayType() const;
   bool isIncompleteArrayType() const;
@@ -363,13 +366,14 @@
   // Type Checking Functions: Check to see if this type is structurally the
   // specified type, ignoring typedefs and qualifiers, and return a pointer to
   // the best type we can.
-  const BuiltinType *getAsBuiltinType() const;   
-  const FunctionType *getAsFunctionType() const;   
-  const FunctionTypeProto *getAsFunctionTypeProto() const;   
+  const BuiltinType *getAsBuiltinType() const;
+  const FunctionType *getAsFunctionType() const;
+  const FunctionTypeProto *getAsFunctionTypeProto() const;
   const PointerLikeType *getAsPointerLikeType() const; // Pointer or Reference.
   const PointerType *getAsPointerType() const;
   const BlockPointerType *getAsBlockPointerType() const;
   const ReferenceType *getAsReferenceType() const;
+  const MemberPointerType *getAsMemberPointerType() const;
   const RecordType *getAsRecordType() const;
   const RecordType *getAsStructureType() const;
   /// NOTE: getAs*ArrayType are methods on ASTContext.
@@ -665,6 +669,53 @@
 
   static bool classof(const Type *T) { return T->getTypeClass() == Reference; }
   static bool classof(const ReferenceType *) { return true; }
+
+protected:
+  virtual void EmitImpl(llvm::Serializer& S) const;
+  static Type* CreateImpl(ASTContext& Context, llvm::Deserializer& D);
+  friend class Type;
+};
+
+/// MemberPointerType - C++ 8.3.3 - Pointers to members
+///
+class MemberPointerType : public Type, public llvm::FoldingSetNode {
+  QualType PointeeType;
+  /// The class of which the pointee is a member. Must ultimately be a
+  /// RecordType, but could be a typedef or a template parameter too.
+  const Type *Class;
+
+  MemberPointerType(QualType Pointee, const Type *Cls, QualType CanonicalPtr) :
+    Type(MemberPointer, CanonicalPtr,
+         Cls->isDependentType() || Pointee->isDependentType()),
+    PointeeType(Pointee), Class(Cls) {
+  }
+  friend class ASTContext; // ASTContext creates these.
+public:
+
+  QualType getPointeeType() const { return PointeeType; }
+
+  const Type *getClass() const { return Class; }
+
+  virtual void getAsStringInternal(std::string &InnerString) const;
+
+  void Profile(llvm::FoldingSetNodeID &ID) {
+    Profile(ID, getPointeeType(), getClass());
+  }
+  static void Profile(llvm::FoldingSetNodeID &ID, QualType Pointee,
+                      const Type *Class) {
+    ID.AddPointer(Pointee.getAsOpaquePtr());
+    ID.AddPointer(Class);
+  }
+
+  static bool classof(const Type *T) {
+    return T->getTypeClass() == MemberPointer;
+  }
+  static bool classof(const MemberPointerType *) { return true; }
+
+protected:
+  virtual void EmitImpl(llvm::Serializer& S) const;
+  static Type* CreateImpl(ASTContext& Context, llvm::Deserializer& D);
+  friend class Type;
 };
 
 /// ArrayType - C99 6.7.5.2 - Array Declarators.
@@ -1576,6 +1627,15 @@
   else
     return false;
 }
+inline bool Type::isMemberPointerType() const {
+  return isa<MemberPointerType>(CanonicalType.getUnqualifiedType());
+}
+inline bool Type::isMemberFunctionPointerType() const {
+  if (const MemberPointerType* T = getAsMemberPointerType())
+    return T->getPointeeType()->isFunctionType();
+  else
+    return false;
+}
 inline bool Type::isArrayType() const {
   return isa<ArrayType>(CanonicalType.getUnqualifiedType());
 }

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=62934&r1=62933&r2=62934&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Sat Jan 24 15:16:55 2009
@@ -1161,6 +1161,10 @@
      "'%0' declared as array of references")
 DIAG(err_illegal_decl_pointer_to_reference, ERROR,
      "'%0' declared as a pointer to a reference")
+DIAG(err_illegal_decl_mempointer_to_void, ERROR,
+     "'%0' declared as a member pointer to void")
+DIAG(err_illegal_decl_mempointer_in_nonclass, ERROR,
+     "'%0' does not point into a class")
 DIAG(err_illegal_decl_reference_to_reference, ERROR,
      "%0 declared as a reference to a reference")
 DIAG(err_invalid_reference_qualifier_application, ERROR,

Modified: cfe/trunk/include/clang/Parse/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/DeclSpec.h?rev=62934&r1=62933&r2=62934&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Parse/DeclSpec.h Sat Jan 24 15:16:55 2009
@@ -429,9 +429,9 @@
 /// This is intended to be a small value object.
 struct DeclaratorChunk {
   enum {
-    Pointer, Reference, Array, Function, BlockPointer
+    Pointer, Reference, Array, Function, BlockPointer, MemberPointer
   } Kind;
-  
+
   /// Loc - The place where this type was defined.
   SourceLocation Loc;
   
@@ -544,39 +544,64 @@
     void destroy() {}
   };
 
+  struct MemberPointerTypeInfo {
+    /// The type qualifiers: const/volatile/restrict.
+    unsigned TypeQuals : 3;
+    AttributeList *AttrList;
+    // CXXScopeSpec has a constructor, so it can't be a direct member.
+    // So we need some pointer-aligned storage and a bit of trickery.
+    union {
+      void *Aligner;
+      char Mem[sizeof(CXXScopeSpec)];
+    } ScopeMem;
+    CXXScopeSpec &Scope() {
+      return *reinterpret_cast<CXXScopeSpec*>(ScopeMem.Mem);
+    }
+    const CXXScopeSpec &Scope() const {
+      return *reinterpret_cast<const CXXScopeSpec*>(ScopeMem.Mem);
+    }
+    void destroy() {
+      delete AttrList;
+      Scope().~CXXScopeSpec();
+    }
+  };
+
   union {
-    PointerTypeInfo      Ptr;
-    ReferenceTypeInfo    Ref;
-    ArrayTypeInfo        Arr;
-    FunctionTypeInfo     Fun;
-    BlockPointerTypeInfo Cls;
+    PointerTypeInfo       Ptr;
+    ReferenceTypeInfo     Ref;
+    ArrayTypeInfo         Arr;
+    FunctionTypeInfo      Fun;
+    BlockPointerTypeInfo  Cls;
+    MemberPointerTypeInfo Mem;
   };
-  
+
   void destroy() {
     switch (Kind) {
     default: assert(0 && "Unknown decl type!");
-    case DeclaratorChunk::Function:     return Fun.destroy();
-    case DeclaratorChunk::Pointer:      return Ptr.destroy();
-    case DeclaratorChunk::BlockPointer: return Cls.destroy();
-    case DeclaratorChunk::Reference:    return Ref.destroy();
-    case DeclaratorChunk::Array:        return Arr.destroy();
+    case DeclaratorChunk::Function:      return Fun.destroy();
+    case DeclaratorChunk::Pointer:       return Ptr.destroy();
+    case DeclaratorChunk::BlockPointer:  return Cls.destroy();
+    case DeclaratorChunk::Reference:     return Ref.destroy();
+    case DeclaratorChunk::Array:         return Arr.destroy();
+    case DeclaratorChunk::MemberPointer: return Mem.destroy();
     }
   }
-  
+
   /// getAttrs - If there are attributes applied to this declaratorchunk, return
   /// them.
   const AttributeList *getAttrs() const {
     switch (Kind) {
     default: assert(0 && "Unknown declarator kind!");
-    case Pointer:   return Ptr.AttrList;
-    case Reference: return Ref.AttrList;
-    case Array:    return 0;
-    case Function:  return 0;
-    case BlockPointer: return 0; // FIXME: Do blocks have attr list?
+    case Pointer:       return Ptr.AttrList;
+    case Reference:     return Ref.AttrList;
+    case MemberPointer: return Mem.AttrList;
+    case Array:         return 0;
+    case Function:      return 0;
+    case BlockPointer:  return 0; // FIXME: Do blocks have attr list?
     }
   }
-  
-  
+
+
   /// getPointer - Return a DeclaratorChunk for a pointer.
   ///
   static DeclaratorChunk getPointer(unsigned TypeQuals, SourceLocation Loc,
@@ -633,6 +658,19 @@
     I.Cls.TypeQuals = TypeQuals;
     return I;
   }
+
+  static DeclaratorChunk getMemberPointer(const CXXScopeSpec &SS,
+                                          unsigned TypeQuals,
+                                          SourceLocation Loc,
+                                          AttributeList *AL) {
+    DeclaratorChunk I;
+    I.Kind          = MemberPointer;
+    I.Loc           = Loc;
+    I.Mem.TypeQuals = TypeQuals;
+    I.Mem.AttrList  = AL;
+    new (I.Mem.ScopeMem.Mem) CXXScopeSpec(SS);
+    return I;
+  }
 };
 
 /// Declarator - Information about one declarator, including the parsed type

Modified: cfe/trunk/include/clang/Parse/Ownership.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Ownership.h?rev=62934&r1=62933&r2=62934&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Ownership.h (original)
+++ cfe/trunk/include/clang/Parse/Ownership.h Sat Jan 24 15:16:55 2009
@@ -103,7 +103,7 @@
 // conversions.
 
 // Flip this switch to measure performance impact of the smart pointers.
-//#define DISABLE_SMART_POINTERS
+#define DISABLE_SMART_POINTERS
 
 namespace clang
 {

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=62934&r1=62933&r2=62934&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Sat Jan 24 15:16:55 2009
@@ -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, 

Modified: cfe/trunk/lib/AST/Type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Type.cpp?rev=62934&r1=62933&r2=62934&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Type.cpp (original)
+++ cfe/trunk/lib/AST/Type.cpp Sat Jan 24 15:16:55 2009
@@ -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());

Modified: cfe/trunk/lib/AST/TypeSerialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TypeSerialization.cpp?rev=62934&r1=62933&r2=62934&view=diff

==============================================================================
--- cfe/trunk/lib/AST/TypeSerialization.cpp (original)
+++ cfe/trunk/lib/AST/TypeSerialization.cpp Sat Jan 24 15:16:55 2009
@@ -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
 //===----------------------------------------------------------------------===//
 

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=62934&r1=62933&r2=62934&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Sat Jan 24 15:16:55 2009
@@ -1550,10 +1550,10 @@
 /// isn't parsed at all, making this function effectively parse the C++
 /// ptr-operator production.
 ///
-///       declarator: [C99 6.7.5]
-///         pointer[opt] direct-declarator
-/// [C++]   '&' declarator [C++ 8p4, dcl.decl]
-/// [GNU]   '&' restrict[opt] attributes[opt] declarator
+///       declarator: [C99 6.7.5] [C++ 8p4, dcl.decl]
+/// [C]     pointer[opt] direct-declarator
+/// [C++]   direct-declarator
+/// [C++]   ptr-operator declarator
 ///
 ///       pointer: [C99 6.7.5]
 ///         '*' type-qualifier-list[opt]
@@ -1563,11 +1563,41 @@
 ///         '*' cv-qualifier-seq[opt]
 ///         '&'
 /// [GNU]   '&' restrict[opt] attributes[opt]
-///         '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] [TODO]
+///         '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt]
 void Parser::ParseDeclaratorInternal(Declarator &D,
                                      DirectDeclParseFunction DirectDeclParser) {
-  tok::TokenKind Kind = Tok.getKind();
 
+  // C++ member pointers start with a '::' or a nested-name.
+  // Member pointers get special handling, since there's no place for the
+  // scope spec in the generic path below.
+  if ((Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
+       Tok.is(tok::annot_cxxscope)) && getLang().CPlusPlus) {
+    CXXScopeSpec SS;
+    if (ParseOptionalCXXScopeSpecifier(SS)) {
+      if(Tok.isNot(tok::star)) {
+        // The scope spec really belongs to the direct-declarator.
+        D.getCXXScopeSpec() = SS;
+        if (DirectDeclParser)
+          (this->*DirectDeclParser)(D);
+        return;
+      }
+
+      SourceLocation Loc = ConsumeToken();
+      DeclSpec DS;
+      ParseTypeQualifierListOpt(DS);
+
+      // Recurse to parse whatever is left.
+      ParseDeclaratorInternal(D, DirectDeclParser);
+
+      // Sema will have to catch (syntactically invalid) pointers into global
+      // scope. It has to catch pointers into namespace scope anyway.
+      D.AddTypeInfo(DeclaratorChunk::getMemberPointer(SS,DS.getTypeQualifiers(),
+                                                      Loc,DS.TakeAttributes()));
+      return;
+    }
+  }
+
+  tok::TokenKind Kind = Tok.getKind();
   // Not a pointer, C++ reference, or block.
   if (Kind != tok::star && (Kind != tok::amp || !getLang().CPlusPlus) &&
       (Kind != tok::caret || !getLang().Blocks)) {
@@ -1575,16 +1605,16 @@
       (this->*DirectDeclParser)(D);
     return;
   }
-  
+
   // Otherwise, '*' -> pointer, '^' -> block, '&' -> reference.
   SourceLocation Loc = ConsumeToken();  // Eat the * or &.
 
   if (Kind == tok::star || (Kind == tok::caret && getLang().Blocks)) {
     // Is a pointer.
     DeclSpec DS;
-    
+
     ParseTypeQualifierListOpt(DS);
-  
+
     // Recursively parse the declarator.
     ParseDeclaratorInternal(D, DirectDeclParser);
     if (Kind == tok::star)
@@ -1680,7 +1710,9 @@
 
   if (getLang().CPlusPlus) {
     if (D.mayHaveIdentifier()) {
-      bool afterCXXScope = ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec());
+      // ParseDeclaratorInternal might already have parsed the scope.
+      bool afterCXXScope = D.getCXXScopeSpec().isSet() ||
+        ParseOptionalCXXScopeSpecifier(D.getCXXScopeSpec());
       if (afterCXXScope) {
         // Change the declaration context for name lookup, until this function
         // is exited (and the declarator has been parsed).

Modified: cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp?rev=62934&r1=62933&r2=62934&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCXXScopeSpec.cpp Sat Jan 24 15:16:55 2009
@@ -50,6 +50,7 @@
       return cast<DeclContext>(SD);
     }
 
+    // FIXME: Template parameters and dependent types.
     // FIXME: C++0x scoped enums
 
     // Fall through to produce an error: we found something that isn't

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=62934&r1=62933&r2=62934&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Sat Jan 24 15:16:55 2009
@@ -287,9 +287,9 @@
           !T->isIncompleteOrObjectType()) {
         Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
           << T;
-        DeclType.Ptr.TypeQuals &= QualType::Restrict;
-      }        
-        
+        DeclType.Ptr.TypeQuals &= ~QualType::Restrict;
+      }
+
       // Apply the pointer typequals to the pointer object.
       T = Context.getPointerType(T).getQualifiedType(DeclType.Ptr.TypeQuals);
       break;
@@ -424,7 +424,7 @@
       }
       break;
     }
-    case DeclaratorChunk::Function:
+    case DeclaratorChunk::Function: {
       // If the function declarator has a prototype (i.e. it is not () and
       // does not have a K&R-style identifier list), then the arguments are part
       // of the type, otherwise the argument list is ().
@@ -518,7 +518,54 @@
       }
       break;
     }
-    
+    case DeclaratorChunk::MemberPointer:
+      // The scope spec must refer to a class, or be dependent.
+      DeclContext *DC = static_cast<DeclContext*>(
+        DeclType.Mem.Scope().getScopeRep());
+      QualType ClsType;
+      // FIXME: Extend for dependent types when it's actually supported.
+      // See ActOnCXXNestedNameSpecifier.
+      if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC)) {
+        ClsType = Context.getTagDeclType(RD);
+      } else {
+        if (DC) {
+          Diag(DeclType.Mem.Scope().getBeginLoc(),
+               diag::err_illegal_decl_mempointer_in_nonclass)
+            << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name")
+            << DeclType.Mem.Scope().getRange();
+        }
+        D.setInvalidType(true);
+        ClsType = Context.IntTy;
+      }
+
+      // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member
+      //   with reference type, or "cv void."
+      if (T->isReferenceType()) {
+        Diag(DeclType.Loc, diag::err_illegal_decl_pointer_to_reference)
+          << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
+        D.setInvalidType(true);
+        T = Context.IntTy;
+      }
+      if (T->isVoidType()) {
+        Diag(DeclType.Loc, diag::err_illegal_decl_mempointer_to_void)
+          << (D.getIdentifier() ? D.getIdentifier()->getName() : "type name");
+        T = Context.IntTy;
+      }
+
+      // Enforce C99 6.7.3p2: "Types other than pointer types derived from
+      // object or incomplete types shall not be restrict-qualified."
+      if ((DeclType.Mem.TypeQuals & QualType::Restrict) &&
+          !T->isIncompleteOrObjectType()) {
+        Diag(DeclType.Loc, diag::err_typecheck_invalid_restrict_invalid_pointee)
+          << T;
+        DeclType.Mem.TypeQuals &= ~QualType::Restrict;
+      }
+
+      T = Context.getMemberPointerType(T, ClsType.getTypePtr());
+
+      break;
+    }
+
     // See if there are any attributes on this declarator chunk.
     if (const AttributeList *AL = DeclType.getAttrs())
       ProcessTypeAttributeList(T, AL);

Added: cfe/trunk/test/SemaCXX/member-pointer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-pointer.cpp?rev=62934&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/member-pointer.cpp (added)
+++ cfe/trunk/test/SemaCXX/member-pointer.cpp Sat Jan 24 15:16:55 2009
@@ -0,0 +1,14 @@
+// RUN: clang -fsyntax-only -verify %s
+
+struct A {};
+enum B { Dummy };
+namespace C {}
+
+int A::*pdi1;
+int (::A::*pdi2);
+int (A::*pfi)(int);
+
+int B::*pbi; // expected-error {{expected a class or namespace}}
+int C::*pci; // expected-error {{'pci' does not point into a class}}
+void A::*pdv; // expected-error {{'pdv' declared as a member pointer to void}}
+int& A::*pdr; // expected-error {{'pdr' declared as a pointer to a reference}}





More information about the cfe-commits mailing list