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
//===----------------------------------------------------------------------===//
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 7f5c098..0ac9e08 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -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).
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 0c0fa35..699f890 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -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
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index ecae793..21db14a 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -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);