Refactor our handling of implicit member reference expressions to get most of the logic out of BuildDeclarationNameExpr

llvm-svn: 84847
This commit is contained in:
Douglas Gregor 2009-10-22 07:08:30 +00:00
parent 3615b9bef3
commit 6493d9c27e
3 changed files with 104 additions and 83 deletions

View 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
//

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

View 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);
}