]> granicus.if.org Git - clang/commitdiff
Allow taking the address of data members, resulting in a member pointer.
authorSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 3 Feb 2009 20:19:35 +0000 (20:19 +0000)
committerSebastian Redl <sebastian.redl@getdesigned.at>
Tue, 3 Feb 2009 20:19:35 +0000 (20:19 +0000)
Pointers to functions don't work yet, and pointers to overloaded functions even less. Also, far too much illegal code is accepted.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63655 91177308-0d34-0410-b5e6-96231b3b80d8

Driver/PrintParserCallbacks.cpp
include/clang/Parse/Action.h
include/clang/Parse/Parser.h
lib/Parse/ParseExpr.cpp
lib/Parse/ParseExprCXX.cpp
lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
test/SemaCXX/member-pointer.cpp

index 9178fcb6fc60c0a599d06197d3de920fa1054416..90cdf45270794456ec4a98a781068a72586fcba6 100644 (file)
@@ -447,7 +447,8 @@ namespace {
     virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
                                                  IdentifierInfo &II,
                                                  bool HasTrailingLParen,
-                                                 const CXXScopeSpec *SS) {
+                                                 const CXXScopeSpec *SS,
+                                                 bool isAddressOfOperand) {
       llvm::cout << __FUNCTION__ << "\n";
       return ExprEmpty();
     }
@@ -455,7 +456,8 @@ namespace {
     virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(
                                Scope *S, SourceLocation OperatorLoc,
                                OverloadedOperatorKind Op,
-                               bool HasTrailingLParen, const CXXScopeSpec &SS) {
+                               bool HasTrailingLParen, const CXXScopeSpec &SS,
+                               bool isAddressOfOperand) {
       llvm::cout << __FUNCTION__ << "\n";
       return ExprEmpty();
     }
@@ -463,7 +465,7 @@ namespace {
     virtual OwningExprResult ActOnCXXConversionFunctionExpr(
                                Scope *S, SourceLocation OperatorLoc,
                                TypeTy *Type, bool HasTrailingLParen,
-                               const CXXScopeSpec &SS) {
+                               const CXXScopeSpec &SS,bool isAddressOfOperand) {
       llvm::cout << __FUNCTION__ << "\n";
       return ExprEmpty();
     }
index 3daf2d553e23d250d90454b95e86afcda107aa9a..ffbb346380b879731f822e5bcc2457a422d81b39 100644 (file)
@@ -551,7 +551,8 @@ public:
   virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
                                                IdentifierInfo &II,
                                                bool HasTrailingLParen,
-                                               const CXXScopeSpec *SS = 0) {
+                                               const CXXScopeSpec *SS = 0,
+                                               bool isAddressOfOperand = false){
     return ExprEmpty();
   }
 
@@ -563,7 +564,8 @@ public:
   virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(
                              Scope *S, SourceLocation OperatorLoc,
                              OverloadedOperatorKind Op,
-                             bool HasTrailingLParen, const CXXScopeSpec &SS) {
+                             bool HasTrailingLParen, const CXXScopeSpec &SS,
+                             bool isAddressOfOperand = false) {
     return ExprEmpty();
   }
 
@@ -575,7 +577,8 @@ public:
   virtual OwningExprResult ActOnCXXConversionFunctionExpr(
                              Scope *S, SourceLocation OperatorLoc,
                              TypeTy *Type, bool HasTrailingLParen,
-                             const CXXScopeSpec &SS) {
+                             const CXXScopeSpec &SS,
+                             bool isAddressOfOperand = false) {
     return ExprEmpty();
   }
 
index d7c957fc47626cb4346d13ddad65ec0dc27dce12..e19100dc10456e228f7d68d4503fce5cc676621c 100644 (file)
@@ -572,7 +572,8 @@ private:
 
   OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS,
                                               unsigned MinPrec);
-  OwningExprResult ParseCastExpression(bool isUnaryExpression);
+  OwningExprResult ParseCastExpression(bool isUnaryExpression,
+                                       bool isAddressOfOperand = false);
   OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS);
   OwningExprResult ParseSizeofAlignofExpression();
   OwningExprResult ParseBuiltinPrimaryExpression();
@@ -609,7 +610,7 @@ private:
 
   //===--------------------------------------------------------------------===//
   // C++ Expressions
-  OwningExprResult ParseCXXIdExpression();
+  OwningExprResult ParseCXXIdExpression(bool isAddressOfOperand = false);
 
   /// ParseOptionalCXXScopeSpecifier - Parse global scope or
   /// nested-name-specifier if present.  Returns true if a nested-name-specifier
index c4df632cc8cd1a9e37d220340da9db09a1af51a1..64c4c31fc46147a469b5a76a454be7ed96767c81 100644 (file)
@@ -345,7 +345,9 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
 }
 
 /// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
-/// true, parse a unary-expression.
+/// true, parse a unary-expression. isAddressOfOperand exists because an
+/// id-expression that is the operand of address-of gets special treatment
+/// due to member pointers.
 ///
 ///       cast-expression: [C99 6.5.4]
 ///         unary-expression
@@ -451,7 +453,8 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) {
 /// [GNU] binary-type-trait:
 ///                   '__is_base_of'                          [TODO]
 ///
-Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
+Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
+                                                     bool isAddressOfOperand) {
   OwningExprResult Res(Actions);
   tok::TokenKind SavedKind = Tok.getKind();
   
@@ -522,7 +525,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
     if (getLang().CPlusPlus) {
       // If TryAnnotateTypeOrScopeToken annotates the token, tail recurse.
       if (TryAnnotateTypeOrScopeToken())
-        return ParseCastExpression(isUnaryExpression);
+        return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
     }
 
     // Consume the identifier so that we can see if it is followed by a '('.
@@ -570,7 +573,15 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
       Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move_arg(Res));
     return move(Res);
   }
-  case tok::amp:           // unary-expression: '&' cast-expression
+  case tok::amp: {         // unary-expression: '&' cast-expression
+    // Special treatment because of member pointers
+    SourceLocation SavedLoc = ConsumeToken();
+    Res = ParseCastExpression(false, true);
+    if (!Res.isInvalid())
+      Res = Actions.ActOnUnaryOp(CurScope, SavedLoc, SavedKind, move_arg(Res));
+    return move(Res);
+  }
+
   case tok::star:          // unary-expression: '*' cast-expression
   case tok::plus:          // unary-expression: '+' cast-expression
   case tok::minus:         // unary-expression: '-' cast-expression
@@ -662,15 +673,15 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression) {
   case tok::annot_cxxscope: // [C++] id-expression: qualified-id
   case tok::kw_operator: // [C++] id-expression: operator/conversion-function-id
                          //                      template-id
-    Res = ParseCXXIdExpression();
+    Res = ParseCXXIdExpression(isAddressOfOperand);
     return ParsePostfixExpressionSuffix(move(Res));
 
   case tok::coloncolon: {
     // ::foo::bar -> global qualified name etc.   If TryAnnotateTypeOrScopeToken
     // annotates the token, tail recurse.
     if (TryAnnotateTypeOrScopeToken())
-      return ParseCastExpression(isUnaryExpression);
-    
+      return ParseCastExpression(isUnaryExpression, isAddressOfOperand);
+
     // ::new -> [C++] new-expression
     // ::delete -> [C++] delete-expression
     SourceLocation CCLoc = ConsumeToken();
index f434cfb1f719f3d58db1b8048ceb8a9f548cf48d..1efa274083213c87fb802044a8b450960516b0de 100644 (file)
@@ -131,7 +131,12 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
 /// That way Sema can handle and report similar errors for namespaces and the
 /// global scope.
 ///
-Parser::OwningExprResult Parser::ParseCXXIdExpression() {
+/// The isAddressOfOperand parameter indicates that this id-expression is a
+/// direct operand of the address-of operator. This is, besides member contexts,
+/// the only place where a qualified-id naming a non-static class member may
+/// appear.
+///
+Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
   // qualified-id:
   //   '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
   //   '::' unqualified-id
@@ -154,18 +159,20 @@ Parser::OwningExprResult Parser::ParseCXXIdExpression() {
     // Consume the identifier so that we can see if it is followed by a '('.
     IdentifierInfo &II = *Tok.getIdentifierInfo();
     SourceLocation L = ConsumeToken();
-    return Actions.ActOnIdentifierExpr(CurScope, L, II,
-                                       Tok.is(tok::l_paren), &SS);
+    return Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren),
+                                       &SS, isAddressOfOperand);
   }
 
   case tok::kw_operator: {
     SourceLocation OperatorLoc = Tok.getLocation();
     if (OverloadedOperatorKind Op = TryParseOperatorFunctionId())
       return Actions.ActOnCXXOperatorFunctionIdExpr(
-                   CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS);
+                       CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS,
+                       isAddressOfOperand);
     if (TypeTy *Type = ParseConversionFunctionId())
       return Actions.ActOnCXXConversionFunctionExpr(CurScope, OperatorLoc, Type,
-                                                    Tok.is(tok::l_paren), SS);
+                                                    Tok.is(tok::l_paren), SS,
+                                                    isAddressOfOperand);
 
     // We already complained about a bad conversion-function-id,
     // above.
index 0969cd03872f3187a2d8e55febeaf0779721a49c..6360dcc44f15631b9fbd2513a71f75e923fda4e2 100644 (file)
@@ -1030,17 +1030,20 @@ public:
   virtual OwningExprResult ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
                                                IdentifierInfo &II,
                                                bool HasTrailingLParen,
-                                               const CXXScopeSpec *SS = 0);
+                                               const CXXScopeSpec *SS = 0,
+                                               bool isAddressOfOperand = false);
   virtual OwningExprResult ActOnCXXOperatorFunctionIdExpr(Scope *S,
                                                     SourceLocation OperatorLoc,
                                                     OverloadedOperatorKind Op,
                                                     bool HasTrailingLParen,
-                                                    const CXXScopeSpec &SS);
+                                                    const CXXScopeSpec &SS,
+                                                    bool isAddressOfOperand);
   virtual OwningExprResult ActOnCXXConversionFunctionExpr(Scope *S,
                                                     SourceLocation OperatorLoc,
                                                     TypeTy *Ty,
                                                     bool HasTrailingLParen,
-                                                    const CXXScopeSpec &SS);
+                                                    const CXXScopeSpec &SS,
+                                                    bool isAddressOfOperand);
   DeclRefExpr *BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
                                 bool TypeDependent, bool ValueDependent,
                                 const CXXScopeSpec *SS = 0);
@@ -1053,7 +1056,8 @@ public:
                                             DeclarationName Name,
                                             bool HasTrailingLParen,
                                             const CXXScopeSpec *SS,
-                                            bool ForceResolution = false);
+                                            bool ForceResolution = false,
+                                            bool isAddressOfOperand = false);
 
   virtual OwningExprResult ActOnPredefinedExpr(SourceLocation Loc,
                                                tok::TokenKind Kind);
index ddd5349c1564605f77a3a37616891332d2cc5800..36107e88ddd0cf4fd01a6071fb5d4b228325757f 100644 (file)
@@ -363,16 +363,19 @@ static bool ShouldSnapshotBlockValueReference(BlockSemaInfo *CurBlock,
 Sema::OwningExprResult Sema::ActOnIdentifierExpr(Scope *S, SourceLocation Loc,
                                                  IdentifierInfo &II,
                                                  bool HasTrailingLParen,
-                                                 const CXXScopeSpec *SS) {
-  return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS);
+                                                 const CXXScopeSpec *SS,
+                                                 bool isAddressOfOperand) {
+  return ActOnDeclarationNameExpr(S, Loc, &II, HasTrailingLParen, SS,
+                                  /*ForceResolution*/false, isAddressOfOperand);
 }
 
 /// BuildDeclRefExpr - Build either a DeclRefExpr or a
 /// QualifiedDeclRefExpr based on whether or not SS is a
 /// nested-name-specifier.
-DeclRefExpr *Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
-                                    bool TypeDependent, bool ValueDependent,
-                                    const CXXScopeSpec *SS) {
+DeclRefExpr *
+Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
+                       bool TypeDependent, bool ValueDependent,
+                       const CXXScopeSpec *SS) {
   if (SS && !SS->isEmpty())
     return new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent, 
                        ValueDependent, SS->getRange().getBegin());
@@ -535,10 +538,16 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
 /// If ForceResolution is true, then we will attempt to resolve the
 /// name even if it looks like a dependent name. This option is off by
 /// default.
+///
+/// isAddressOfOperand means that this expression is the direct operand
+/// of an address-of operator. This matters because this is the only
+/// situation where a qualified name referencing a non-static member may
+/// appear outside a member function of this class.
 Sema::OwningExprResult
 Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
                                DeclarationName Name, bool HasTrailingLParen,
-                               const CXXScopeSpec *SS, bool ForceResolution) {
+                               const CXXScopeSpec *SS, bool ForceResolution,
+                               bool isAddressOfOperand) {
   if (S->getTemplateParamParent() && Name.getAsIdentifierInfo() &&
       HasTrailingLParen && !SS && !ForceResolution) {
     // We've seen something of the form
@@ -554,11 +563,11 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
   }
 
   // Could be enum-constant, value decl, instance variable, etc.
-  Decl *D = 0;
   if (SS && SS->isInvalid())
     return ExprError();
   LookupResult Lookup = LookupParsedName(S, SS, Name, LookupOrdinaryName);
 
+  Decl *D = 0;
   if (Lookup.isAmbiguous()) {
     DiagnoseAmbiguousLookup(Lookup, Name, Loc,
                             SS && SS->isSet() ? SS->getRange()
@@ -618,6 +627,41 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
     }
   }
 
+  // If this is an expression of the form &Class::member, don't build an
+  // implicit member ref, because we want a pointer to the member in general,
+  // not any specific instance's member.
+  if (isAddressOfOperand && SS && !SS->isEmpty() && !HasTrailingLParen) {
+    NamedDecl *ND = dyn_cast<NamedDecl>(D);
+    DeclContext *DC = static_cast<DeclContext*>(SS->getScopeRep());
+    if (ND && isa<CXXRecordDecl>(DC)) {
+      QualType DType;
+      if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+        DType = FD->getType().getNonReferenceType();
+      } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
+        DType = Method->getType();
+      } else if (isa<OverloadedFunctionDecl>(D)) {
+        DType = Context.OverloadTy;
+      }
+      // Could be an inner type. That's diagnosed below, so ignore it here.
+      if (!DType.isNull()) {
+        // The pointer is type- and value-dependent if it points into something
+        // dependent.
+        bool Dependent = false;
+        for (; DC; DC = DC->getParent()) {
+          // FIXME: could stop early at namespace scope.
+          if (DC->isRecord()) {
+            CXXRecordDecl *Record = cast<CXXRecordDecl>(DC);
+            if (Context.getTypeDeclType(Record)->isDependentType()) {
+              Dependent = true;
+              break;
+            }
+          }
+        }
+        return Owned(BuildDeclRefExpr(ND, DType, Loc, Dependent, Dependent,SS));
+      }
+    }
+  }
+
   // We may have found a field within an anonymous union or struct
   // (C++ [class.union]).
   if (FieldDecl *FD = dyn_cast<FieldDecl>(D))
@@ -3428,6 +3472,14 @@ QualType Sema::CheckAddressOfOperand(Expr *op, SourceLocation OpLoc) {
       return Context.OverloadTy;
     } else if (isa<FieldDecl>(dcl)) {
       // Okay: we can take the address of a field.
+      // Could be a pointer to member, though, if there is an explicit
+      // scope qualifier for the class.
+      if (isa<QualifiedDeclRefExpr>(op)) {
+        DeclContext *Ctx = dcl->getDeclContext();
+        if (Ctx && Ctx->isRecord())
+          return Context.getMemberPointerType(op->getType(),
+                Context.getTypeDeclType(cast<RecordDecl>(Ctx)).getTypePtr());
+      }
     } else if (isa<FunctionDecl>(dcl)) {
       // Okay: we can take the address of a function.
     }
index 3c8184d24d83254f0ef5e4f4598281be2aee6654..e9dbc849b00b3cd654d107e34ad79755dd4c2c3c 100644 (file)
@@ -28,13 +28,14 @@ using namespace clang;
 Sema::OwningExprResult
 Sema::ActOnCXXConversionFunctionExpr(Scope *S, SourceLocation OperatorLoc,
                                      TypeTy *Ty, bool HasTrailingLParen,
-                                     const CXXScopeSpec &SS) {
+                                     const CXXScopeSpec &SS,
+                                     bool isAddressOfOperand) {
   QualType ConvType = QualType::getFromOpaquePtr(Ty);
   QualType ConvTypeCanon = Context.getCanonicalType(ConvType);
   DeclarationName ConvName 
     = Context.DeclarationNames.getCXXConversionFunctionName(ConvTypeCanon);
   return ActOnDeclarationNameExpr(S, OperatorLoc, ConvName, HasTrailingLParen,
-                                  &SS);
+                                  &SS, /*ForceRes*/false, isAddressOfOperand);
 }
 
 /// ActOnCXXOperatorFunctionIdExpr - Parse a C++ overloaded operator
@@ -46,9 +47,11 @@ Sema::OwningExprResult
 Sema::ActOnCXXOperatorFunctionIdExpr(Scope *S, SourceLocation OperatorLoc,
                                      OverloadedOperatorKind Op,
                                      bool HasTrailingLParen,
-                                     const CXXScopeSpec &SS) {
+                                     const CXXScopeSpec &SS,
+                                     bool isAddressOfOperand) {
   DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(Op);
-  return ActOnDeclarationNameExpr(S, OperatorLoc, Name, HasTrailingLParen, &SS);
+  return ActOnDeclarationNameExpr(S, OperatorLoc, Name, HasTrailingLParen, &SS,
+                                  /*ForceRes*/false, isAddressOfOperand);
 }
 
 /// ActOnCXXTypeidOfType - Parse typeid( type-id ).
index 31973c1257007640e3991825d05f106b2bd65294..450fdba367f28dfb0a96cd74a999981c4ab3698a 100644 (file)
@@ -40,3 +40,23 @@ void f() {
   // Conversion to member of base.
   pdi1 = pdid; // expected-error {{incompatible type assigning 'int struct D::*', expected 'int struct A::*'}}
 }
+
+struct HasMembers
+{
+  int i;
+  void f();
+};
+
+namespace Fake
+{
+  int i;
+  void f();
+}
+
+void g() {
+  int HasMembers::*pmi = &HasMembers::i;
+  int *pni = &Fake::i;
+
+  // FIXME: Test the member function, too.
+  void (*pnf)() = &Fake::f;
+}