diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-10-22 07:08:30 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-10-22 07:08:30 +0000 |
commit | e961afbf3f5604b043773192de77effa207cbe8c (patch) | |
tree | 05b1e6a6509f97e868cdc287abd4b3fed2680ab9 | |
parent | 9fcfe926432f3c3f7e9a61219e55c352fd358e45 (diff) |
Refactor our handling of implicit member reference expressions to get most of the logic out of BuildDeclarationNameExpr
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84847 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 102 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 81 |
3 files changed, 104 insertions, 83 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 30418c03bd..e636563aa3 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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 // diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 5f00293d39..ae45429952 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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)) { diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 2dc99b3596..d4d031f91e 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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); +} + |