diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 121 | ||||
-rw-r--r-- | test/SemaCXX/member-pointer.cpp | 3 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-member-pointers.cpp | 27 | ||||
-rw-r--r-- | test/SemaTemplate/temp_class_spec.cpp | 10 |
7 files changed, 132 insertions, 47 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 4b9b7037e1..0d0a10eed0 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1001,6 +1001,8 @@ def err_illegal_decl_mempointer_to_void : Error< "'%0' declared as a member pointer to void">; def err_illegal_decl_mempointer_in_nonclass : Error< "'%0' does not point into a class">; +def err_mempointer_in_nonclass_type : Error< + "member pointer refers into non-class type %0">; def err_reference_to_void : Error<"cannot form a reference to 'void'">; def err_qualified_block_pointer_type : Error< "qualifier specification on block pointer type not allowed">; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index c5582935db..12ebc4adff 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -349,6 +349,9 @@ public: QualType *ParamTypes, unsigned NumParamTypes, bool Variadic, unsigned Quals, SourceLocation Loc, DeclarationName Entity); + QualType BuildMemberPointerType(QualType T, QualType Class, + unsigned Quals, SourceLocation Loc, + DeclarationName Entity); QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0, TagDecl **OwnedDecl = 0); DeclarationName GetNameForDeclarator(Declarator &D); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 562749e18f..c1f67c78ad 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -265,9 +265,16 @@ QualType TemplateTypeInstantiator:: InstantiateMemberPointerType(const MemberPointerType *T, unsigned Quals) const { - // FIXME: Implement this - assert(false && "Cannot instantiate MemberPointerType yet"); - return QualType(); + QualType PointeeType = Instantiate(T->getPointeeType()); + if (PointeeType.isNull()) + return QualType(); + + QualType ClassType = Instantiate(QualType(T->getClass(), 0)); + if (ClassType.isNull()) + return QualType(); + + return SemaRef.BuildMemberPointerType(PointeeType, ClassType, Quals, Loc, + Entity); } QualType diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index cd19d97c5b..6c2a4dc2d0 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -600,7 +600,67 @@ QualType Sema::BuildFunctionType(QualType T, return Context.getFunctionType(T, ParamTypes, NumParamTypes, Variadic, Quals); } - + +/// \brief Build a member pointer type \c T Class::*. +/// +/// \param T the type to which the member pointer refers. +/// \param Class the class type into which the member pointer points. +/// \param Quals Qualifiers applied to the member pointer type +/// \param Loc the location where this type begins +/// \param Entity the name of the entity that will have this member pointer type +/// +/// \returns a member pointer type, if successful, or a NULL type if there was +/// an error. +QualType Sema::BuildMemberPointerType(QualType T, QualType Class, + unsigned Quals, SourceLocation Loc, + DeclarationName Entity) { + // Verify that we're not building a pointer to pointer to function with + // exception specification. + if (CheckDistantExceptionSpec(T)) { + Diag(Loc, diag::err_distant_exception_spec); + + // FIXME: If we're doing this as part of template instantiation, + // we should return immediately. + + // Build the type anyway, but use the canonical type so that the + // exception specifiers are stripped off. + T = Context.getCanonicalType(T); + } + + // C++ 8.3.3p3: A pointer to member shall not pointer to ... a member + // with reference type, or "cv void." + if (T->isReferenceType()) { + Diag(Loc, diag::err_illegal_decl_pointer_to_reference) + << (Entity? Entity.getAsString() : "type name"); + return QualType(); + } + + if (T->isVoidType()) { + Diag(Loc, diag::err_illegal_decl_mempointer_to_void) + << (Entity? Entity.getAsString() : "type name"); + return QualType(); + } + + // Enforce C99 6.7.3p2: "Types other than pointer types derived from + // object or incomplete types shall not be restrict-qualified." + if ((Quals & QualType::Restrict) && !T->isIncompleteOrObjectType()) { + Diag(Loc, diag::err_typecheck_invalid_restrict_invalid_pointee) + << T; + + // FIXME: If we're doing this as part of template instantiation, + // we should return immediately. + Quals &= ~QualType::Restrict; + } + + if (!Class->isDependentType() && !Class->isRecordType()) { + Diag(Loc, diag::err_mempointer_in_nonclass_type) << Class; + return QualType(); + } + + return Context.getMemberPointerType(T, Class.getTypePtr()) + .getQualifiedType(Quals); +} + /// GetTypeForDeclarator - Convert the type for the specified /// declarator to Type instances. Skip the outermost Skip type /// objects. @@ -870,57 +930,32 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip, break; } case DeclaratorChunk::MemberPointer: - // Verify that we're not building a pointer to pointer to function with - // exception specification. - if (getLangOptions().CPlusPlus && CheckDistantExceptionSpec(T)) { - Diag(D.getIdentifierLoc(), diag::err_distant_exception_spec); - D.setInvalidType(true); - // Build the type anyway. - } // The scope spec must refer to a class, or be dependent. - DeclContext *DC = computeDeclContext(DeclType.Mem.Scope()); QualType ClsType; - // FIXME: Extend for dependent types when it's actually supported. - // See ActOnCXXNestedNameSpecifier. - if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC)) { + if (isDependentScopeSpecifier(DeclType.Mem.Scope())) { + NestedNameSpecifier *NNS + = (NestedNameSpecifier *)DeclType.Mem.Scope().getScopeRep(); + assert(NNS->getAsType() && "Nested-name-specifier must name a type"); + ClsType = QualType(NNS->getAsType(), 0); + } else if (CXXRecordDecl *RD + = dyn_cast_or_null<CXXRecordDecl>( + computeDeclContext(DeclType.Mem.Scope()))) { 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(); - } + 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"); + if (!ClsType.isNull()) + T = BuildMemberPointerType(T, ClsType, DeclType.Mem.TypeQuals, + DeclType.Loc, D.getIdentifier()); + if (T.isNull()) { T = Context.IntTy; + D.setInvalidType(true); } - - // 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()). - getQualifiedType(DeclType.Mem.TypeQuals); - break; } diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp index cfe4f75dd1..d2df5eb317 100644 --- a/test/SemaCXX/member-pointer.cpp +++ b/test/SemaCXX/member-pointer.cpp @@ -12,7 +12,8 @@ int A::*pdi1; int (::A::*pdi2); int (A::*pfi)(int); -int B::*pbi; // expected-error {{expected a class or namespace}} +int B::*pbi; // expected-error {{expected a class or namespace}} \ + // expected-error{{does not point into a class}} 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}} diff --git a/test/SemaTemplate/instantiate-member-pointers.cpp b/test/SemaTemplate/instantiate-member-pointers.cpp new file mode 100644 index 0000000000..b3ddb3fafa --- /dev/null +++ b/test/SemaTemplate/instantiate-member-pointers.cpp @@ -0,0 +1,27 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +struct Y { + int x; +}; + +template<typename T> +struct X1 { + int f(T* ptr, int T::*pm) { // expected-error{{member pointer}} + return ptr->*pm; + } +}; + +template struct X1<Y>; +template struct X1<int>; // expected-note{{instantiation}} + +template<typename T, typename Class> +struct X2 { + T f(Class &obj, T Class::*pm) { // expected-error{{to a reference}} \ + // expected-error{{member pointer to void}} + return obj.*pm; + } +}; + +template struct X2<int, Y>; +template struct X2<int&, Y>; // expected-note{{instantiation}} +template struct X2<const void, Y>; // expected-note{{instantiation}} diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp index e17691cf62..709fa4201f 100644 --- a/test/SemaTemplate/temp_class_spec.cpp +++ b/test/SemaTemplate/temp_class_spec.cpp @@ -148,3 +148,13 @@ struct is_binary_function<R(T1, T2)> { }; int is_binary_function0[is_binary_function<int(float, double)>::value? 1 : -1]; + +template<typename T> +struct is_member_pointer { + static const bool value = false; +}; + +template<typename T, typename Class> +struct is_member_pointer<T Class::*> { + static const bool value = true; +}; |