Add support for declaring pointers to members.
Add serialization support for ReferenceType. llvm-svn: 62934
This commit is contained in:
parent
04964bbebe
commit
9ed6efdd75
|
@ -60,6 +60,7 @@ class ASTContext {
|
|||
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 @@ public:
|
|||
/// 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,
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace clang {
|
|||
class PointerType;
|
||||
class BlockPointerType;
|
||||
class ReferenceType;
|
||||
class MemberPointerType;
|
||||
class VectorType;
|
||||
class ArrayType;
|
||||
class ConstantArrayType;
|
||||
|
@ -66,7 +67,7 @@ namespace clang {
|
|||
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 @@ namespace clang {
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
// 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 @@ public:
|
|||
|
||||
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 @@ inline bool Type::isFunctionPointerType() const {
|
|||
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());
|
||||
}
|
||||
|
|
|
@ -1161,6 +1161,10 @@ DIAG(err_illegal_decl_array_of_references, ERROR,
|
|||
"'%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,
|
||||
|
|
|
@ -429,9 +429,9 @@ typedef llvm::SmallVector<Token, 4> CachedTokens;
|
|||
/// 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 @@ struct DeclaratorChunk {
|
|||
void destroy() {}
|
||||
};
|
||||
|
||||
union {
|
||||
PointerTypeInfo Ptr;
|
||||
ReferenceTypeInfo Ref;
|
||||
ArrayTypeInfo Arr;
|
||||
FunctionTypeInfo Fun;
|
||||
BlockPointerTypeInfo Cls;
|
||||
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;
|
||||
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 @@ struct DeclaratorChunk {
|
|||
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
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -85,6 +85,7 @@ void ASTContext::PrintStats() const {
|
|||
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 @@ void ASTContext::PrintStats() const {
|
|||
++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 @@ void ASTContext::PrintStats() const {
|
|||
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 @@ void ASTContext::PrintStats() const {
|
|||
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 @@ ASTContext::getTypeInfo(const Type *T) {
|
|||
// 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 @@ QualType ASTContext::getReferenceType(QualType T) {
|
|||
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,
|
||||
|
|
|
@ -288,6 +288,24 @@ const ReferenceType *Type::getAsReferenceType() const {
|
|||
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 @@ bool Type::isVariablyModifiedType() const {
|
|||
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 @@ bool Type::isScalarType() const {
|
|||
return ASQT->getBaseType()->isScalarType();
|
||||
return isa<PointerType>(CanonicalType) ||
|
||||
isa<BlockPointerType>(CanonicalType) ||
|
||||
isa<MemberPointerType>(CanonicalType) ||
|
||||
isa<ComplexType>(CanonicalType) ||
|
||||
isa<ObjCQualifiedIdType>(CanonicalType);
|
||||
}
|
||||
|
@ -702,9 +724,9 @@ bool Type::isPODType() const {
|
|||
case Builtin:
|
||||
case Complex:
|
||||
case Pointer:
|
||||
case MemberPointer:
|
||||
case Vector:
|
||||
case ExtVector:
|
||||
// FIXME: pointer-to-member
|
||||
return true;
|
||||
|
||||
case Tagged:
|
||||
|
@ -951,6 +973,20 @@ void ReferenceType::getAsStringInternal(std::string &S) const {
|
|||
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());
|
||||
|
|
|
@ -93,21 +93,29 @@ void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) {
|
|||
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 @@ void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) {
|
|||
break;
|
||||
|
||||
case Type::VariableArray:
|
||||
D.RegisterPtr(PtrID,VariableArrayType::CreateImpl(Context,D));
|
||||
D.RegisterPtr(PtrID, VariableArrayType::CreateImpl(Context, D));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -242,6 +250,33 @@ Type* PointerType::CreateImpl(ASTContext& Context, Deserializer& D) {
|
|||
return Context.getPointerType(QualType::ReadVal(D)).getTypePtr();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -1550,10 +1550,10 @@ void Parser::ParseDeclarator(Declarator &D) {
|
|||
/// 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 @@ void Parser::ParseDeclarator(Declarator &D) {
|
|||
/// '*' 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 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
|
|||
(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 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
|
|||
|
||||
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).
|
||||
|
|
|
@ -50,6 +50,7 @@ Sema::CXXScopeTy *Sema::ActOnCXXNestedNameSpecifier(Scope *S,
|
|||
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
|
||||
|
|
|
@ -287,9 +287,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
|
|||
!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 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
|
|||
}
|
||||
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 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
|
|||
}
|
||||
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);
|
||||
|
|
|
@ -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}}
|
Loading…
Reference in New Issue