diff options
author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-01-28 18:33:18 +0000 |
---|---|---|
committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-01-28 18:33:18 +0000 |
commit | 21593acb933324b439bc68b68e7cc7d1c3e3484d (patch) | |
tree | 6feee8a9f735cae4af555e7a7395a67e696d226d | |
parent | 66973121788ca645fe3d4a66179b9cfb6f2bce08 (diff) |
Implement pointer to member handling in static_cast.
Fix a stupid mistake in UnwrapSimilarPointers that made any two member pointers compatible as long as the pointee was the same.
Make a few style corrections as suggested by Chris.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63215 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.def | 6 | ||||
-rw-r--r-- | lib/Sema/SemaInherit.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaNamedCast.cpp | 67 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 85 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/member-pointer.cpp | 3 | ||||
-rw-r--r-- | test/SemaCXX/static-cast.cpp | 12 | ||||
-rw-r--r-- | www/cxx_status.html | 4 |
8 files changed, 133 insertions, 57 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 6cc23dd427..2959f6186b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -999,9 +999,9 @@ DIAG(err_duplicate_base_class, ERROR, // FIXME: better way to display derivation? Pass entire thing into diagclient? DIAG(err_ambiguous_derived_to_base_conv, ERROR, "ambiguous conversion from derived class %0 to base class %1:%2") -DIAG(err_ambiguous_base_to_derived_memptr_conv, ERROR, - "ambiguous conversion from pointer to member of base class %0 " - "to pointer to member of derived class %1:%2") +DIAG(err_ambiguous_memptr_conv, ERROR, + "ambiguous conversion from pointer to member of %select{base|derived}0 " + "class %1 to pointer to member of %select{derived|base}0 class %2:%3") DIAG(err_memptr_conv_via_virtual, ERROR, "conversion from pointer to member of class %0 to pointer to member " "of class %1 via virtual base %2 is not allowed") diff --git a/lib/Sema/SemaInherit.cpp b/lib/Sema/SemaInherit.cpp index b5bd8939ad..307c527504 100644 --- a/lib/Sema/SemaInherit.cpp +++ b/lib/Sema/SemaInherit.cpp @@ -218,9 +218,9 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, /*DetectVirtual=*/false); bool DerivationOkay = IsDerivedFrom(Derived, Base, Paths); - assert(DerivationOkay && "Can only be used with a derived-to-base conversion"); - if (!DerivationOkay) - return true; + assert(DerivationOkay && + "Can only be used with a derived-to-base conversion"); + (void)DerivationOkay; if (!Paths.isAmbiguous(Context.getCanonicalType(Base).getUnqualifiedType())) return false; @@ -235,8 +235,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, Paths.setRecordingPaths(true); bool StillOkay = IsDerivedFrom(Derived, Base, Paths); assert(StillOkay && "Can only be used with a derived-to-base conversion"); - if (!StillOkay) - return true; + (void)StillOkay; // Build up a textual representation of the ambiguous paths, e.g., // D -> B -> A, that will be used to illustrate the ambiguous diff --git a/lib/Sema/SemaNamedCast.cpp b/lib/Sema/SemaNamedCast.cpp index e88a3b2079..cac76b63e4 100644 --- a/lib/Sema/SemaNamedCast.cpp +++ b/lib/Sema/SemaNamedCast.cpp @@ -44,6 +44,8 @@ static TryStaticCastResult TryStaticReferenceDowncast( Sema &Self, Expr *SrcExpr, QualType DestType, const SourceRange &OpRange); static TryStaticCastResult TryStaticPointerDowncast( Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange); +static TryStaticCastResult TryStaticMemberPointerUpcast( + Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange); static TryStaticCastResult TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType, const SourceRange &OpRange, @@ -479,10 +481,13 @@ CheckStaticCast(Sema &Self, Expr *&SrcExpr, QualType DestType, return; } - // Reverse member pointer conversion. C++ 5.11 specifies member pointer + // 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. - // FIXME: Don't have member pointers yet. + if (TryStaticMemberPointerUpcast(Self, SrcType, DestType, OpRange) + > TSC_NotApplicable) { + return; + } // Reverse pointer conversion to void*. C++ 4.10.p2 specifies conversion to // void*. C++ 5.2.9p10 specifies additional restrictions, which really is @@ -655,6 +660,64 @@ TryStaticDowncast(Sema &Self, QualType SrcType, QualType DestType, return TSC_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 CXXRecordType *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; +} + /// TryStaticImplicitCast - Tests whether a conversion according to C++ 5.2.9p2 /// is valid: /// diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index b2ae90b4b8..0f9f0cf9c6 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -1087,51 +1087,50 @@ bool Sema::IsMemberPointerConversion(Expr *From, QualType FromType, /// otherwise. bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType) { QualType FromType = From->getType(); + const MemberPointerType *FromPtrType = FromType->getAsMemberPointerType(); + if (!FromPtrType) + return false; - if (const MemberPointerType *FromPtrType = - FromType->getAsMemberPointerType()) { - if (const MemberPointerType *ToPtrType = - ToType->getAsMemberPointerType()) { - QualType FromClass = QualType(FromPtrType->getClass(), 0); - QualType ToClass = QualType(ToPtrType->getClass(), 0); - - // FIXME: What about dependent types? - assert(FromClass->isRecordType() && "Pointer into non-class."); - assert(ToClass->isRecordType() && "Pointer into non-class."); - - BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, - /*DetectVirtual=*/true); - bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths); - assert(DerivationOkay && - "Should not have been called if derivation isn't OK."); - if (!DerivationOkay) - return true; - - if (Paths.isAmbiguous(Context.getCanonicalType(FromClass). - getUnqualifiedType())) { - // Derivation is ambiguous. Redo the check to find the exact paths. - Paths.clear(); - Paths.setRecordingPaths(true); - bool StillOkay = IsDerivedFrom(ToClass, FromClass, Paths); - assert(StillOkay && "Derivation changed due to quantum fluctuation."); - if (!StillOkay) - return true; - - std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths); - Diag(From->getExprLoc(), - diag::err_ambiguous_base_to_derived_memptr_conv) - << FromClass << ToClass << PathDisplayStr << From->getSourceRange(); - return true; - } + const MemberPointerType *ToPtrType = ToType->getAsMemberPointerType(); + assert(ToPtrType && "No member pointer cast has a target type " + "that is not a member pointer."); + + QualType FromClass = QualType(FromPtrType->getClass(), 0); + QualType ToClass = QualType(ToPtrType->getClass(), 0); + + // FIXME: What about dependent types? + assert(FromClass->isRecordType() && "Pointer into non-class."); + assert(ToClass->isRecordType() && "Pointer into non-class."); + + BasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/false, + /*DetectVirtual=*/true); + bool DerivationOkay = IsDerivedFrom(ToClass, FromClass, Paths); + assert(DerivationOkay && + "Should not have been called if derivation isn't OK."); + (void)DerivationOkay; + + if (Paths.isAmbiguous(Context.getCanonicalType(FromClass). + getUnqualifiedType())) { + // Derivation is ambiguous. Redo the check to find the exact paths. + Paths.clear(); + Paths.setRecordingPaths(true); + bool StillOkay = IsDerivedFrom(ToClass, FromClass, Paths); + assert(StillOkay && "Derivation changed due to quantum fluctuation."); + (void)StillOkay; + + std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths); + Diag(From->getExprLoc(), diag::err_ambiguous_memptr_conv) + << 0 << FromClass << ToClass << PathDisplayStr << From->getSourceRange(); + return true; + } - if (const CXXRecordType *VBase = Paths.getDetectedVirtual()) { - Diag(From->getExprLoc(), diag::err_memptr_conv_via_virtual) - << FromClass << ToClass << QualType(VBase, 0) - << From->getSourceRange(); - return true; - } - } + if (const CXXRecordType *VBase = Paths.getDetectedVirtual()) { + Diag(From->getExprLoc(), diag::err_memptr_conv_via_virtual) + << FromClass << ToClass << QualType(VBase, 0) + << From->getSourceRange(); + return true; } + return false; } @@ -1148,7 +1147,7 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType) // qualification conversion. if (FromType == ToType) return false; - + // (C++ 4.4p4): // A conversion can add cv-qualifiers at levels other than the first // in multi-level pointers, subject to the following rules: [...] diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 60219fe292..5d54f463ea 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -662,7 +662,9 @@ bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2) const MemberPointerType *T1MPType = T1->getAsMemberPointerType(), *T2MPType = T2->getAsMemberPointerType(); - if (T1MPType && T2MPType) { + if (T1MPType && T2MPType && + Context.getCanonicalType(T1MPType->getClass()) == + Context.getCanonicalType(T2MPType->getClass())) { T1 = T1MPType->getPointeeType(); T2 = T2MPType->getPointeeType(); return true; diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp index bcd3dd65e8..31973c1257 100644 --- a/test/SemaCXX/member-pointer.cpp +++ b/test/SemaCXX/member-pointer.cpp @@ -36,4 +36,7 @@ void f() { // Fail conversion due to ambiguity and virtuality. int F::*pdif = pdi1; // expected-error {{ambiguous conversion from pointer to member of base class 'struct A' to pointer to member of derived class 'struct F'}} expected-error {{incompatible type}} int G::*pdig = pdi1; // expected-error {{conversion from pointer to member of class 'struct A' to pointer to member of class 'struct G' via virtual base 'struct D' is not allowed}} expected-error {{incompatible type}} + + // Conversion to member of base. + pdi1 = pdid; // expected-error {{incompatible type assigning 'int struct D::*', expected 'int struct A::*'}} } diff --git a/test/SemaCXX/static-cast.cpp b/test/SemaCXX/static-cast.cpp index 464ea79aed..9bbcdf670b 100644 --- a/test/SemaCXX/static-cast.cpp +++ b/test/SemaCXX/static-cast.cpp @@ -42,6 +42,8 @@ void t_529_2() (void)static_cast<B&>(*((C1*)0)); (void)static_cast<A*>((D*)0); (void)static_cast<const A&>(*((D*)0)); + (void)static_cast<int B::*>((int A::*)0); + (void)static_cast<void (B::*)()>((void (A::*)())0); // TODO: User-defined conversions @@ -116,4 +118,12 @@ void t_529_10() (void)static_cast<void (*)()>((void*)0); // expected-error {{static_cast from 'void *' to 'void (*)(void)' is not allowed}} } -// TODO: Test member pointers. +// Member pointer upcast. +void t_529_9() +{ + (void)static_cast<int A::*>((int B::*)0); + + // Bad code below + (void)static_cast<int A::*>((int H::*)0); // expected-error {{ambiguous conversion from pointer to member of derived class 'struct H'}} + (void)static_cast<int A::*>((int F::*)0); // expected-error {{conversion from pointer to member of class 'struct F'}} +} diff --git a/www/cxx_status.html b/www/cxx_status.html index 22a419af5e..6135b3f49b 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -571,10 +571,10 @@ welcome!</p> <tr>
<td> 5.2.9 [expr.static.cast]</td>
<td class="complete" align="center">✓</td>
+ <td class="complete" align="center">✓</td>
<td class="advanced" align="center"></td>
- <td class="medium" align="center"></td>
<td></td>
- <td>Missing member pointer conversions.</td>
+ <td>Some custom conversions don't work.</td>
</tr>
<tr>
<td> 5.2.10 [expr.reinterpret.cast]</td>
|