forked from OSchip/llvm-project
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:
parent
3615b9bef3
commit
6493d9c27e
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue