/// TryStaticMemberPointerUpcast - Tests whether a conversion according to /// C++ 5.2.9p9 is valid: /// /// An rvalue of type "pointer to member of D of type cv1 T" can be /// converted to an rvalue of type "pointer to member of B of type cv2 T", /// where B is a base class of D [...]. /// TryCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, bool CStyle, const SourceRange &OpRange, unsigned &msg) { const MemberPointerType *DestMemPtr = DestType->getAs<MemberPointerType>(); if (!DestMemPtr) return TC_NotApplicable; const MemberPointerType *SrcMemPtr = SrcType->getAs<MemberPointerType>(); if (!SrcMemPtr) { msg = diag::err_bad_static_cast_member_pointer_nonmp; return TC_NotApplicable; } // T == T, modulo cv if (Self.Context.getCanonicalType( SrcMemPtr->getPointeeType().getUnqualifiedType()) != Self.Context.getCanonicalType(DestMemPtr->getPointeeType(). getUnqualifiedType())) return TC_NotApplicable; // B base of D QualType SrcClass(SrcMemPtr->getClass(), 0); QualType DestClass(DestMemPtr->getClass(), 0); BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/!CStyle, /*DetectVirtual=*/true); if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) { return TC_NotApplicable; } // B is a base of D. But is it an allowed base? If not, it's a hard error. if (Paths.isAmbiguous(DestClass)) { Paths.clear(); Paths.setRecordingPaths(true); bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths); assert(StillOkay); StillOkay = StillOkay; std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths); Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv) << 1 << SrcClass << DestClass << PathDisplayStr << OpRange; msg = 0; return TC_Failed; } if (const RecordType *VBase = Paths.getDetectedVirtual()) { Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual) << SrcClass << DestClass << QualType(VBase, 0) << OpRange; msg = 0; return TC_Failed; } if (!CStyle && Self.CheckBaseClassAccess(DestType, SrcType, diag::err_downcast_from_inaccessible_base, Paths, OpRange.getBegin(), DeclarationName())) { msg = 0; return TC_Failed; } return TC_Success; }
/// TryStaticMemberPointerUpcast - Tests whether a conversion according to /// C++ 5.2.9p9 is valid: /// /// An rvalue of type "pointer to member of D of type cv1 T" can be /// converted to an rvalue of type "pointer to member of B of type cv2 T", /// where B is a base class of D [...]. /// TryStaticCastResult TryStaticMemberPointerUpcast(Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange) { const MemberPointerType *SrcMemPtr = SrcType->getAsMemberPointerType(); if (!SrcMemPtr) return TSC_NotApplicable; const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType(); if (!DestMemPtr) return TSC_NotApplicable; // T == T, modulo cv if (Self.Context.getCanonicalType( SrcMemPtr->getPointeeType().getUnqualifiedType()) != Self.Context.getCanonicalType(DestMemPtr->getPointeeType(). getUnqualifiedType())) return TSC_NotApplicable; // B base of D QualType SrcClass(SrcMemPtr->getClass(), 0); QualType DestClass(DestMemPtr->getClass(), 0); BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, /*DetectVirtual=*/true); if (!Self.IsDerivedFrom(SrcClass, DestClass, Paths)) { return TSC_NotApplicable; } // B is a base of D. But is it an allowed base? If not, it's a hard error. if (Paths.isAmbiguous(DestClass)) { Paths.clear(); Paths.setRecordingPaths(true); bool StillOkay = Self.IsDerivedFrom(SrcClass, DestClass, Paths); assert(StillOkay); StillOkay = StillOkay; std::string PathDisplayStr = Self.getAmbiguousPathsDisplayString(Paths); Self.Diag(OpRange.getBegin(), diag::err_ambiguous_memptr_conv) << 1 << SrcClass << DestClass << PathDisplayStr << OpRange; return TSC_Failed; } if (const RecordType *VBase = Paths.getDetectedVirtual()) { Self.Diag(OpRange.getBegin(), diag::err_memptr_conv_via_virtual) << SrcClass << DestClass << QualType(VBase, 0) << OpRange; return TSC_Failed; } // FIXME: Test accessibility. return TSC_Success; }