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