diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index ac189a0649..5af6f91d14 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -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()); diff --git a/lib/Sema/SemaCXXCast.cpp b/lib/Sema/SemaCXXCast.cpp index 0097cd363c..e04abd2aac 100644 --- a/lib/Sema/SemaCXXCast.cpp +++ b/lib/Sema/SemaCXXCast.cpp @@ -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(); if (!DestMemPtr) return TC_NotApplicable; + + bool WasOverloadedFunction = false; + if (FunctionDecl *Fn + = Self.ResolveAddressOfOverloadedFunction(SrcExpr, DestType, false)) { + CXXMethodDecl *M = cast(Fn); + SrcType = Self.Context.getMemberPointerType(Fn->getType(), + Self.Context.getTypeDeclType(M->getParent()).getTypePtr()); + WasOverloadedFunction = true; + } + const MemberPointerType *SrcMemPtr = SrcType->getAs(); 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; } diff --git a/test/CodeGenCXX/nullptr.cpp b/test/CodeGenCXX/nullptr.cpp index 31bd47522e..ab63b432bd 100644 --- a/test/CodeGenCXX/nullptr.cpp +++ b/test/CodeGenCXX/nullptr.cpp @@ -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(); +} diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp index 4818b041ad..efdc276e7d 100644 --- a/test/SemaCXX/static-cast.cpp +++ b/test/SemaCXX/static-cast.cpp @@ -181,3 +181,17 @@ struct X4 { // PR5897 - accept static_cast from const void* to const int (*)[1]. void PR5897() { (void)static_cast((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(&B::f); + (void)static_cast(&B::f); + (void)static_cast(&B::f); + (void)static_cast(&B::f); // expected-error{{static_cast from '' to 'void (struct PR6072::D::*)()' is not allowed}} + } +}