]> granicus.if.org Git - clang/commitdiff
Refactor our handling of implicit member reference expressions to get most of the...
authorDouglas Gregor <dgregor@apple.com>
Thu, 22 Oct 2009 07:08:30 +0000 (07:08 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 22 Oct 2009 07:08:30 +0000 (07:08 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84847 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/Sema.h
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp

index 30418c03bd9d8c5a58d28b65e6512af28ce80dcb..e636563aa3c6e46d0ae1b83f996115c292586024 100644 (file)
@@ -2353,6 +2353,10 @@ public:
                                  FunctionDecl::StorageClass& SC);
   DeclPtrTy ActOnConversionDeclarator(CXXConversionDecl *Conversion);
 
+  bool isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D,
+                                 SourceLocation NameLoc, QualType &ThisType,
+                                 QualType &MemberType);
+  
   //===--------------------------------------------------------------------===//
   // C++ Derived Classes
   //
index 5f00293d3983ba7b748bb08bce968b35bfdf049d..ae45429952c7efb1864b3148749f8f557eaa70a6 100644 (file)
@@ -941,95 +941,31 @@ Sema::BuildDeclarationNameExpr(SourceLocation Loc, NamedDecl *D,
 
   // We may have found a field within an anonymous union or struct
   // (C++ [class.union]).
+  // FIXME: This needs to happen post-isImplicitMemberReference?
   if (FieldDecl *FD = dyn_cast<FieldDecl>(D))
     if (cast<RecordDecl>(FD->getDeclContext())->isAnonymousStructOrUnion())
       return BuildAnonymousStructUnionMemberReference(Loc, FD);
 
-  if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext)) {
-    if (!MD->isStatic()) {
-      // C++ [class.mfct.nonstatic]p2:
-      //   [...] if name lookup (3.4.1) resolves the name in the
-      //   id-expression to a nonstatic nontype member of class X or of
-      //   a base class of X, the id-expression is transformed into a
-      //   class member access expression (5.2.5) using (*this) (9.3.2)
-      //   as the postfix-expression to the left of the '.' operator.
-      DeclContext *Ctx = 0;
-      QualType MemberType;
-      if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
-        Ctx = FD->getDeclContext();
-        MemberType = FD->getType();
-
-        if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>())
-          MemberType = RefType->getPointeeType();
-        else if (!FD->isMutable())
-          MemberType
-            = Context.getQualifiedType(MemberType,
-                            Qualifiers::fromCVRMask(MD->getTypeQualifiers()));
-      } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {
-        if (!Method->isStatic()) {
-          Ctx = Method->getParent();
-          MemberType = Method->getType();
-        }
-      } else if (FunctionTemplateDecl *FunTmpl
-                   = dyn_cast<FunctionTemplateDecl>(D)) {
-        if (CXXMethodDecl *Method
-              = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl())) {
-          if (!Method->isStatic()) {
-            Ctx = Method->getParent();
-            MemberType = Context.OverloadTy;
-          }
-        }
-      } else if (OverloadedFunctionDecl *Ovl
-                   = dyn_cast<OverloadedFunctionDecl>(D)) {
-        // FIXME: We need an abstraction for iterating over one or more function
-        // templates or functions. This code is far too repetitive!
-        for (OverloadedFunctionDecl::function_iterator
-               Func = Ovl->function_begin(),
-               FuncEnd = Ovl->function_end();
-             Func != FuncEnd; ++Func) {
-          CXXMethodDecl *DMethod = 0;
-          if (FunctionTemplateDecl *FunTmpl
-                = dyn_cast<FunctionTemplateDecl>(*Func))
-            DMethod = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
-          else
-            DMethod = dyn_cast<CXXMethodDecl>(*Func);
-
-          if (DMethod && !DMethod->isStatic()) {
-            Ctx = DMethod->getDeclContext();
-            MemberType = Context.OverloadTy;
-            break;
-          }
-        }
-      }
-
-      if (Ctx && Ctx->isRecord()) {
-        QualType CtxType = Context.getTagDeclType(cast<CXXRecordDecl>(Ctx));
-        QualType ThisType = Context.getTagDeclType(MD->getParent());
-        if ((Context.getCanonicalType(CtxType)
-               == Context.getCanonicalType(ThisType)) ||
-            IsDerivedFrom(ThisType, CtxType)) {
-          // Build the implicit member access expression.
-          Expr *This = new (Context) CXXThisExpr(SourceLocation(),
-                                                 MD->getThisType(Context));
-          MarkDeclarationReferenced(Loc, D);
-          if (PerformObjectMemberConversion(This, D))
-            return ExprError();
-
-          bool ShouldCheckUse = true;
-          if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
-            // Don't diagnose the use of a virtual member function unless it's
-            // explicitly qualified.
-            if (MD->isVirtual() && (!SS || !SS->isSet()))
-              ShouldCheckUse = false;
-          }
+  // Cope with an implicit member access in a C++ non-static member function.
+  QualType ThisType, MemberType;
+  if (isImplicitMemberReference(SS, D, Loc, ThisType, MemberType)) {
+    Expr *This = new (Context) CXXThisExpr(SourceLocation(), ThisType);
+    MarkDeclarationReferenced(Loc, D);
+    if (PerformObjectMemberConversion(This, D))
+      return ExprError();
 
-          if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc))
-            return ExprError();
-          return Owned(BuildMemberExpr(Context, This, true, SS, D,
-                                       Loc, MemberType));
-        }
-      }
+    bool ShouldCheckUse = true;
+    if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) {
+      // Don't diagnose the use of a virtual member function unless it's
+      // explicitly qualified.
+      if (MD->isVirtual() && (!SS || !SS->isSet()))
+        ShouldCheckUse = false;
     }
+
+    if (ShouldCheckUse && DiagnoseUseOfDecl(D, Loc))
+      return ExprError();
+    return Owned(BuildMemberExpr(Context, This, true, SS, D,
+                                 Loc, MemberType));
   }
 
   if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
index 2dc99b3596d3f665e5ff0357de1350b566ff46ff..d4d031f91ed56cef016f96d9d34eb1e0c7ac4581 100644 (file)
@@ -2276,3 +2276,84 @@ Sema::OwningExprResult Sema::ActOnFinishFullExpr(ExprArg Arg) {
 
   return Owned(FullExpr);
 }
+
+/// \brief Determine whether a reference to the given declaration in the 
+/// current context is an implicit member access 
+/// (C++ [class.mfct.non-static]p2).
+///
+/// FIXME: Should Objective-C also use this approach?
+///
+/// \param SS if non-NULL, the C++ nested-name-specifier that precedes the 
+/// name of the declaration referenced.
+///
+/// \param D the declaration being referenced from the current scope.
+///
+/// \param NameLoc the location of the name in the source.
+///
+/// \param ThisType if the reference to this declaration is an implicit member
+/// access, will be set to the type of the "this" pointer to be used when
+/// building that implicit member access.
+///
+/// \param MemberType if the reference to this declaration is an implicit
+/// member access, will be set to the type of the member being referenced
+/// (for use at the type of the resulting member access expression).
+///
+/// \returns true if this is an implicit member reference (in which case 
+/// \p ThisType and \p MemberType will be set), or false if it is not an
+/// implicit member reference.
+bool Sema::isImplicitMemberReference(const CXXScopeSpec *SS, NamedDecl *D,
+                                     SourceLocation NameLoc, QualType &ThisType,
+                                     QualType &MemberType) {
+  // If this isn't a C++ method, then it isn't an implicit member reference.
+  CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CurContext);
+  if (!MD || MD->isStatic())
+    return false;
+  
+  // C++ [class.mfct.nonstatic]p2:
+  //   [...] if name lookup (3.4.1) resolves the name in the
+  //   id-expression to a nonstatic nontype member of class X or of
+  //   a base class of X, the id-expression is transformed into a
+  //   class member access expression (5.2.5) using (*this) (9.3.2)
+  //   as the postfix-expression to the left of the '.' operator.
+  DeclContext *Ctx = 0;
+  if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+    Ctx = FD->getDeclContext();
+    MemberType = FD->getType();
+    
+    if (const ReferenceType *RefType = MemberType->getAs<ReferenceType>())
+      MemberType = RefType->getPointeeType();
+    else if (!FD->isMutable())
+      MemberType
+        = Context.getQualifiedType(MemberType,
+                           Qualifiers::fromCVRMask(MD->getTypeQualifiers()));
+  } else {
+    for (OverloadIterator Ovl(D), OvlEnd; Ovl != OvlEnd; ++Ovl) {
+      CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(*Ovl);
+      FunctionTemplateDecl *FunTmpl = 0;
+      if (!Method && (FunTmpl = dyn_cast<FunctionTemplateDecl>(*Ovl)))
+        Method = dyn_cast<CXXMethodDecl>(FunTmpl->getTemplatedDecl());
+      
+      if (Method && !Method->isStatic()) {
+        Ctx = Method->getParent();
+        if (isa<CXXMethodDecl>(D) && !FunTmpl)
+          MemberType = Method->getType();
+        else
+          MemberType = Context.OverloadTy;
+        break;
+      }
+    }
+  } 
+  
+  if (!Ctx || !Ctx->isRecord())
+    return false;
+  
+  // Determine whether the declaration(s) we found are actually in a base 
+  // class. If not, this isn't an implicit member reference.
+  ThisType = MD->getThisType(Context);
+  QualType CtxType = Context.getTypeDeclType(cast<CXXRecordDecl>(Ctx));
+  QualType ClassType
+    = Context.getTypeDeclType(cast<CXXRecordDecl>(MD->getParent()));
+  return Context.hasSameType(CtxType, ClassType) || 
+         IsDerivedFrom(ClassType, CtxType);
+}
+