[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

Douglas Gregor dgregor at apple.com
Sat Jan 24 14:21:35 PST 2009


On Jan 24, 2009, at 1:16 PM, Sebastian Redl wrote:

> 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.


This is awesome, thank you! There's a boat-load of FIXMEs regarding  
conversions and overloading that involve pointers to members, most of  
which will be relatively easy to deal with now that you've done the  
parsing and representation bits.


> +
> +  /// 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);

So, I have to ask: should we use the term "PointerToMember" rather  
than "MemberPointer" throughout? "Pointer to member" is the term used  
in the standard.

(There are a handful of other things I'd like to rename along these  
lines; CXXMethodDecl->MemberFunction, EnumDecl->EnumerationDecl,  
EnumConstantDecl->EnumeratorDecl, etc.)

> 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
> @@ -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.
> +  }

Please put a FIXME: in that comment above so we don't forget to  
(eventually) move this into TargetInfo or some future ABI abstraction  
layer.

> /// 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();

The comment doesn't match the code here, since MemberPointerType isn't  
a PointerLikeType.

> = 
> = 
> = 
> = 
> = 
> = 
> = 
> = 
> ======================================================================
> --- 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;
> +      }

Ah, good. I like this non-lookahead approach. Perhaps the  
getLang().CPlusPlus check should go first?

> 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}}


It looks like we'll also need to update the declaration/expression  
ambiguity resolver in lib/Parse/ParseTentative.cpp. Here's a test case  
for that:

void f() {
   int (A::*pf)(int, int);
}

Which currently fails with:

/Users/dgregor/Projects/llvm/tools/clang/test/SemaCXX/member- 
pointer.cpp:18:11: error: expected unqualified-id
   int (A::*pf)(int, int);
           ^
/Users/dgregor/Projects/llvm/tools/clang/test/SemaCXX/member- 
pointer.cpp:18:19: error: expected '(' for function-style cast or type  
construction
   int (A::*pf)(int, int);
                ~~~^

   - Doug



More information about the cfe-commits mailing list