Perform overload resolution when static_cast'ing from a

pointer-to-member-to-derived to a pointer-to-member-to-base. Fixes
PR6072.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@97923 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-03-07 23:24:59 +00:00
Родитель a1a9f03585
Коммит 4ce46c2db2
4 изменённых файлов: 69 добавлений и 5 удалений

Просмотреть файл

@ -178,6 +178,11 @@ void AggExprEmitter::EmitFinalDestCopy(const Expr *E, LValue Src, bool Ignore) {
//===----------------------------------------------------------------------===//
void AggExprEmitter::VisitCastExpr(CastExpr *E) {
if (!DestPtr) {
Visit(E->getSubExpr());
return;
}
switch (E->getCastKind()) {
default: assert(0 && "Unhandled cast kind!");
@ -205,6 +210,11 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) {
break;
case CastExpr::CK_NullToMemberPointer: {
// If the subexpression's type is the C++0x nullptr_t, emit the
// subexpression, which may have side effects.
if (E->getSubExpr()->getType()->isNullPtrType())
Visit(E->getSubExpr());
const llvm::Type *PtrDiffTy =
CGF.ConvertType(CGF.getContext().getPointerDiffType());

Просмотреть файл

@ -84,7 +84,8 @@ static TryCastResult TryStaticDowncast(Sema &Self, CanQualType SrcType,
QualType OrigSrcType,
QualType OrigDestType, unsigned &msg,
CastExpr::CastKind &Kind);
static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType,
static TryCastResult TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr,
QualType SrcType,
QualType DestType,bool CStyle,
const SourceRange &OpRange,
unsigned &msg,
@ -554,7 +555,7 @@ static TryCastResult TryStaticCast(Sema &Self, Expr *&SrcExpr,
// Reverse member pointer conversion. C++ 4.11 specifies member pointer
// conversion. C++ 5.2.9p9 has additional information.
// DR54's access restrictions apply here also.
tcr = TryStaticMemberPointerUpcast(Self, SrcType, DestType, CStyle,
tcr = TryStaticMemberPointerUpcast(Self, SrcExpr, SrcType, DestType, CStyle,
OpRange, msg, Kind);
if (tcr != TC_NotApplicable)
return tcr;
@ -798,12 +799,23 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
/// where B is a base class of D [...].
///
TryCastResult
TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
bool CStyle, const SourceRange &OpRange,
TryStaticMemberPointerUpcast(Sema &Self, Expr *&SrcExpr, QualType SrcType,
QualType DestType, bool CStyle,
const SourceRange &OpRange,
unsigned &msg, CastExpr::CastKind &Kind) {
const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>();
if (!DestMemPtr)
return TC_NotApplicable;
bool WasOverloadedFunction = false;
if (FunctionDecl *Fn
= Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false)) {
CXXMethodDecl *M = cast<CXXMethodDecl>(Fn);
SrcType = Self.Context.getMemberPointerType(Fn->getType(),
Self.Context.getTypeDeclType(M->getParent()).getTypePtr());
WasOverloadedFunction = true;
}
const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>();
if (!SrcMemPtr) {
msg = diag::err_bad_static_cast_member_pointer_nonmp;
@ -853,6 +865,24 @@ TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType,
return TC_Failed;
}
if (WasOverloadedFunction) {
// Resolve the address of the overloaded function again, this time
// allowing complaints if something goes wrong.
FunctionDecl *Fn = Self.ResolveAddressOfOverloadedFunction(SrcExpr,
DestType,
true);
if (!Fn) {
msg = 0;
return TC_Failed;
}
SrcExpr = Self.FixOverloadedFunctionReference(SrcExpr, Fn);
if (!SrcExpr) {
msg = 0;
return TC_Failed;
}
}
Kind = CastExpr::CK_DerivedToBaseMemberPointer;
return TC_Success;
}

Просмотреть файл

@ -1,7 +1,17 @@
// RUN: %clang_cc1 -std=c++0x %s -emit-llvm -o %t
// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s
int* a = nullptr;
void f() {
int* a = nullptr;
}
typedef decltype(nullptr) nullptr_t;
nullptr_t get_nullptr();
struct X { };
void g() {
// CHECK: call i8* @_Z11get_nullptrv()
int (X::*pmf)(int) = get_nullptr();
}

Просмотреть файл

@ -181,3 +181,17 @@ struct X4 {
// PR5897 - accept static_cast from const void* to const int (*)[1].
void PR5897() { (void)static_cast<const int(*)[1]>((const void*)0); }
namespace PR6072 {
struct A { };
struct B : A { void f(int); void f(); };
struct C : B { };
struct D { };
void f() {
(void)static_cast<void (A::*)()>(&B::f);
(void)static_cast<void (B::*)()>(&B::f);
(void)static_cast<void (C::*)()>(&B::f);
(void)static_cast<void (D::*)()>(&B::f); // expected-error{{static_cast from '<overloaded function type>' to 'void (struct PR6072::D::*)()' is not allowed}}
}
}